跳到主要内容Java 处理 JSON 编程实用技巧 | 极客日志Javajava
Java 处理 JSON 编程实用技巧
Java JSON 处理涉及 Gson、Jackson 和 Fastjson 三大主流框架。文章对比了各框架特性,详解基础序列化反序列化、集合处理、注解控制及自定义适配器用法。涵盖性能优化策略如实例复用、流式 API 使用及安全配置建议。提供统一工具类封装示例及常见问题解决方案,帮助开发者在 Spring 项目或高性能场景下选择合适的库并规避反序列化漏洞风险。
imJackJia0 浏览 1. 前言
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于机器解析和生成。在 Java 开发中,JSON 处理是一项非常常见且重要的任务。本文将详细介绍 Java 中处理 JSON 的各种实用技巧,包括主流 JSON 框架的使用、性能优化以及最佳实践。
本文将重点介绍 Gson、Jackson 和 Fastjson 这三个主流 Java JSON 处理库的使用技巧和性能优化方法。
2. JSON 处理框架对比
Java 生态中有多个优秀的 JSON 处理框架,每个框架都有其特点和适用场景。下面是三个主流框架的对比:

3. Gson 使用技巧
3.1 基础用法
Gson 是 Google 开发的 Java 库,用于将 Java 对象转换为 JSON 表示,以及将 JSON 字符串转换回等效的 Java 对象。
3.1.1 Maven 依赖
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
3.1.2 基本序列化与反序列化
Gson gson = new Gson();
User user = new User("张三", 25);
String json = gson.toJson(user);
System.out.println(json);
;
gson.fromJson(jsonString, User.class);
System.out.println(parsedUser.getName());
String
jsonString
=
"{\"name\":\"李四\",\"age\":30}"
User
parsedUser
=
3.1.3 集合类型的序列化与反序列化
List<User> userList = Arrays.asList(
new User("张三", 25),
new User("李四", 30)
);
String jsonList = gson.toJson(userList);
Type userListType = new TypeToken<List<User>>(){}.getType();
List<User> parsedList = gson.fromJson(jsonList, userListType);
User[] userArray = gson.fromJson(jsonList, User[].class);
List<User> userList2 = Arrays.asList(userArray);
3.2 高级特性
3.2.1 GsonBuilder 配置
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(Date.class, new DateSerializer())
.disableHtmlEscaping()
.create();
3.2.2 自定义序列化和反序列化
public class UserSerializer implements JsonSerializer<User> {
@Override
public JsonElement serialize(User user, Type type, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("userName", user.getName());
jsonObject.addProperty("userAge", user.getAge());
return jsonObject;
}
}
public class UserDeserializer implements JsonDeserializer<User> {
@Override
public User deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("userName").getAsString();
int age = jsonObject.get("userAge").getAsInt();
return new User(name, age);
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(User.class, new UserSerializer())
.registerTypeAdapter(User.class, new UserDeserializer())
.create();
3.2.3 使用注解控制序列化
public class User {
@SerializedName("user_name")
private String name;
@SerializedName(value = "user_age", alternate = {"age", "userAge"})
private int age;
@Expose(serialize = true, deserialize = false)
private String password;
@Expose(serialize = false, deserialize = true)
private String email;
}
Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
3.2.4 处理复杂嵌套对象
String complexJson = "{\"name\":\"张三\",\"address\":{\"city\":\"北京\",\"district\":\"朝阳区\"}}";
JsonElement jsonElement = JsonParser.parseString(complexJson);
JsonObject jsonObject = jsonElement.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
JsonObject addressObject = jsonObject.getAsJsonObject("address");
String city = addressObject.get("city").getAsString();
if (jsonObject.has("phone")) {
String phone = jsonObject.get("phone").getAsString();
}
**技巧:**Gson 2.8.6+版本中,JsonParser 的静态方法已被弃用,建议使用以下方式:
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(jsonString));
reader.setLenient(true);
JsonElement jsonElement = gson.fromJson(reader, JsonElement.class);
4. Jackson 使用技巧
4.1 基础用法
Jackson 是一个功能强大的 Java 库,用于处理 JSON 数据格式。它被广泛应用于 Spring 框架中,性能优异且功能丰富。
4.1.1 Maven 依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.13.0</version>
</dependency>
4.1.2 基本序列化与反序列化
ObjectMapper objectMapper = new ObjectMapper();
User user = new User("张三", 25);
String json = objectMapper.writeValueAsString(user);
System.out.println(json);
String jsonString = "{\"name\":\"李四\",\"age\":30}";
User parsedUser = objectMapper.readValue(jsonString, User.class);
System.out.println(parsedUser.getName());
String prettyJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
4.1.3 集合类型的序列化与反序列化
List<User> userList = Arrays.asList(
new User("张三", 25),
new User("李四", 30)
);
String jsonList = objectMapper.writeValueAsString(userList);
List<User> parsedList = objectMapper.readValue(
jsonList,
new TypeReference<List<User>>() {}
);
Map<String, Object> map = objectMapper.readValue(
jsonString,
new TypeReference<Map<String, Object>>() {}
);
4.2 高级特性
4.2.1 ObjectMapper 配置
ObjectMapper objectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(SerializationFeature.INDENT_OUTPUT, true)
.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false)
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.registerModule(new JavaTimeModule());
4.2.2 自定义序列化和反序列化
public class UserSerializer extends JsonSerializer<User> {
@Override
public void serialize(User user, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("userName", user.getName());
jsonGenerator.writeNumberField("userAge", user.getAge());
jsonGenerator.writeEndObject();
}
}
public class UserDeserializer extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
String name = node.get("userName").asText();
int age = node.get("userAge").asInt();
return new User(name, age);
}
}
SimpleModule module = new SimpleModule();
module.addSerializer(User.class, new UserSerializer());
module.addDeserializer(User.class, new UserDeserializer());
objectMapper.registerModule(module);
4.2.3 使用注解控制序列化
public class User {
@JsonProperty("user_name")
private String name;
@JsonIgnore
private String password;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String email;
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List<String> hobbies;
}
4.2.4 处理复杂 JSON 结构
String complexJson = "{\"name\":\"张三\",\"address\":{\"city\":\"北京\",\"district\":\"朝阳区\"}}";
JsonNode rootNode = objectMapper.readTree(complexJson);
String name = rootNode.get("name").asText();
String city = rootNode.get("address").get("city").asText();
if (rootNode.has("phone")) {
String phone = rootNode.get("phone").asText();
}
JsonNode arrayNode = rootNode.get("contacts");
if (arrayNode != null && arrayNode.isArray()) {
for (JsonNode node : arrayNode) {
String contactName = node.get("name").asText();
}
}
4.2.5 使用树模型
ObjectMapper mapper = new ObjectMapper();
ObjectNode rootNode = mapper.createObjectNode();
rootNode.put("name", "张三");
rootNode.put("age", 25);
ObjectNode addressNode = mapper.createObjectNode();
addressNode.put("city", "北京");
addressNode.put("district", "朝阳区");
rootNode.set("address", addressNode);
ArrayNode hobbiesNode = mapper.createArrayNode();
hobbiesNode.add("读书");
hobbiesNode.add("游泳");
rootNode.set("hobbies", hobbiesNode);
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
5. Fastjson 使用技巧
5.1 基础用法
Fastjson 是阿里巴巴开发的 JSON 库,以其极高的性能著称,API 简洁易用。
**安全提示:**Fastjson 历史上存在一些安全漏洞,使用时请确保更新到最新版本,并根据官方建议进行安全配置。
5.1.1 Maven 依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
5.1.2 基本序列化与反序列化
User user = new User("张三", 25);
String json = JSON.toJSONString(user);
System.out.println(json);
String jsonString = "{\"name\":\"李四\",\"age\":30}";
User parsedUser = JSON.parseObject(jsonString, User.class);
System.out.println(parsedUser.getName());
String prettyJson = JSON.toJSONString(user, SerializerFeature.PrettyFormat);
5.1.3 集合类型的序列化与反序列化
List<User> userList = Arrays.asList(
new User("张三", 25),
new User("李四", 30)
);
String jsonList = JSON.toJSONString(userList);
List<User> parsedList = JSON.parseArray(jsonList, User.class);
JSONObject jsonObject = JSON.parseObject(jsonString);
String name = jsonObject.getString("name");
int age = jsonObject.getInteger("age");
5.2 高级特性
5.2.1 SerializerFeature 配置
String json = JSON.toJSONString(user,
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.WriteMapNullValue
);
5.2.2 自定义序列化和反序列化
public class UserSerializer implements ObjectSerializer {
@Override
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
User user = (User) object;
SerializeWriter out = serializer.out;
out.write('{');
out.writeFieldName("userName");
serializer.write(user.getName());
out.write(',');
out.writeFieldName("userAge");
serializer.write(user.getAge());
out.write('}');
}
}
public class UserDeserializer implements ObjectDeserializer {
@Override
public User deserialize(DefaultJSONParser parser, Type type, Object fieldName) {
JSONObject jsonObject = parser.parseObject();
String name = jsonObject.getString("userName");
int age = jsonObject.getInteger("userAge");
return new User(name, age);
}
@Override
public int getFastMatchToken() {
return 0;
}
}
ParserConfig.getGlobalInstance().putDeserializer(User.class, new UserDeserializer());
SerializeConfig.getGlobalInstance().put(User.class, new UserSerializer());
5.2.3 使用注解控制序列化
public class User {
@JSONField(name = "user_name")
private String name;
@JSONField(serialize = false)
private String password;
@JSONField(deserialize = false)
private String token;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
@JSONField(ordinal = 1)
private String email;
}
5.2.4 使用 JSONObject 和 JSONArray
JSONObject jsonObject = new JSONObject();
jsonObject.put("name", "张三");
jsonObject.put("age", 25);
JSONObject addressObject = new JSONObject();
addressObject.put("city", "北京");
addressObject.put("district", "朝阳区");
jsonObject.put("address", addressObject);
JSONArray hobbiesArray = new JSONArray();
hobbiesArray.add("读书");
hobbiesArray.add("游泳");
jsonObject.put("hobbies", hobbiesArray);
String json = jsonObject.toJSONString();
JSONObject parsedObject = JSON.parseObject(complexJson);
String city = parsedObject.getJSONObject("address").getString("city");
JSONArray contacts = parsedObject.getJSONArray("contacts");
for (int i = 0; i < contacts.size(); i++) {
String contactName = contacts.getJSONObject(i).getString("name");
}
5.2.5 安全配置
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
ParserConfig parserConfig = ParserConfig.getGlobalInstance();
parserConfig.addAccept("com.example.model.");
JSONReader jsonReader = new JSONReader(new StringReader(jsonString));
jsonReader.config(Feature.SupportAutoType, false);
6. 性能优化技巧
6.1 通用优化原则
- **重用对象:**避免重复创建 JSON 解析器实例(Gson、ObjectMapper 或 JSON),这些实例是线程安全的
- **避免不必要的转换:**直接在流上进行操作,减少中间字符串的创建
- **选择合适的解析模式:**根据需求选择树模型或流式 API
- **优化数据结构:**减少不必要的嵌套和冗余字段
- **合理使用缓存:**缓存序列化/反序列化的结果
6.2 Gson 性能优化
public class GsonHolder {
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting()
.create();
public static Gson getGson() {
return GSON;
}
}
TypeAdapter<User> userAdapter = GsonHolder.getGson().getAdapter(User.class);
userAdapter.write(new JsonWriter(new FileWriter("user.json")), user);
User user = userAdapter.read(new JsonReader(new FileReader("user.json")));
String json = GsonHolder.getGson().toJson(user);
6.3 Jackson 性能优化
public class ObjectMapperHolder {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
public static ObjectMapper getObjectMapper() {
return OBJECT_MAPPER;
}
}
ObjectMapperHolder.getObjectMapper().writeValue(new File("large.json"), largeObject);
LargeObject largeObject = ObjectMapperHolder.getObjectMapper()
.readValue(new File("large.json"), LargeObject.class);
JsonNode rootNode = ObjectMapperHolder.getObjectMapper().readTree(jsonString);
String neededField = rootNode.get("neededField").asText();
JavaType listType = ObjectMapperHolder.getObjectMapper().getTypeFactory()
.constructCollectionType(List.class, User.class);
6.4 Fastjson 性能优化
List<User> userList = JSON.parseObject(jsonList, new TypeReference<List<User>>() {});
byte[] bytes = JSONB.toJSONBBytes(user);
User parsedUser = JSONB.parseObject(bytes, User.class);
PropertyFilter propertyFilter = new PropertyFilter() {
@Override
public boolean apply(Object object, String name, Object value) {
return !"password".equals(name);
}
};
String json = JSON.toJSONString(user, propertyFilter);
JSONReader reader = new JSONReader(new StringReader(largeJson));
reader.startObject();
while (reader.hasNext()) {
String key = reader.readString();
if ("neededField".equals(key)) {
String value = reader.readString();
} else {
reader.skipValue();
}
}
reader.endObject();
**注意:**性能优化需要根据具体场景进行测试和验证,不同的框架在不同场景下可能有不同的表现。建议使用 JMH 等基准测试工具进行性能对比。
7. 最佳实践
7.1 选择合适的框架
- 如果项目使用 Spring 框架,优先考虑 Jackson
- 如果对性能要求极高,可考虑 Fastjson(注意安全问题)
- 如果追求 API 简洁和易用性,可选择 Gson
7.2 代码组织最佳实践
public class JsonUtils {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static String toJson(Object obj) {
try {
return OBJECT_MAPPER.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON 序列化失败", e);
}
}
public static <T> T fromJson(String json, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(json, clazz);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON 反序列化失败", e);
}
}
public static <T> List<T> fromJsonList(String json, Class<T> clazz) {
try {
return OBJECT_MAPPER.readValue(
json,
OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz)
);
} catch (JsonProcessingException e) {
throw new RuntimeException("JSON 列表反序列化失败", e);
}
}
}
7.3 错误处理和异常管理
try {
User user = JsonUtils.fromJson(jsonString, User.class);
} catch (RuntimeException e) {
log.error("JSON 解析失败:{}", jsonString, e);
throw new BusinessException("数据格式错误,请检查输入");
}
try {
ObjectMapperHolder.getObjectMapper().readTree(jsonString);
} catch (Exception e) {
throw new IllegalArgumentException("无效的 JSON 格式");
}
7.4 安全处理
**安全提示:**处理外部 JSON 数据时,务必注意安全问题,特别是反序列化操作可能导致远程代码执行漏洞。
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
mapper.registerModule(new SimpleModule()
.addDeserializer(Object.class, new SafeObjectDeserializer()));
ParserConfig.getGlobalInstance().setAutoTypeSupport(false);
ParserConfig.getGlobalInstance().addAccept("com.example.model.");
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new SafeTypeAdapterFactory())
.create();
7.5 处理日期时间
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer())
.registerTypeAdapter(LocalDateTime.class, new LocalDateTimeDeserializer())
.create();
String json = JSON.toJSONString(dateObject, SerializerFeature.WriteDateUseDateFormat);
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
String formattedJson = JSON.toJSONString(dateObject, SerializerFeature.WriteDateUseDateFormat);
8. 常见问题与解决方案
8.1 字段名不匹配
**问题:**JSON 中的字段名与 Java 类中的字段名不一致,导致反序列化失败。
- Gson: 使用@SerializedName 注解
- Jackson: 使用@JsonProperty 注解
- Fastjson: 使用@JSONField 注解
8.2 处理 null 值
**问题:**JSON 中包含 null 值,如何控制其序列化和反序列化行为。
- Gson: 使用 GsonBuilder.serializeNulls() 控制
- Jackson: 使用@JsonInclude(JsonInclude.Include.NON_NULL) 注解或配置
- Fastjson: 使用 SerializerFeature.WriteMapNullValue 或@JSONField 注解
8.3 循环引用问题
**问题:**对象之间存在循环引用,导致序列化时出现 StackOverflowError。
- Gson: 默认处理循环引用,但会生成$ref 引用标记
- Jackson: 使用@JsonManagedReference 和@JsonBackReference 注解
- Fastjson: 使用 SerializerFeature.DisableCircularReferenceDetect 禁用循环引用检测
8.4 处理复杂嵌套结构
**问题:**JSON 结构复杂,难以直接映射到 Java 类。
- Gson: 使用 JsonParser 和 JsonElement API
- Jackson: 使用 JsonNode 树模型 API
- Fastjson: 使用 JSONObject 和 JSONArray API
8.5 性能问题
**问题:**处理大型 JSON 数据时性能不佳。
- 重用解析器实例
- 使用流式 API 而不是树模型
- 避免不必要的字符串转换
- 使用更高效的 JSON 库(如需要高性能可考虑 Fastjson)
9. 总结与建议
选择建议
- **Spring 项目:**优先使用 Jackson,与 Spring 框架集成良好
- **对性能要求极高的场景:**考虑 Fastjson,但需注意安全问题
- **追求简洁 API:**Gson 是不错的选择
- **混合环境:**可以根据不同模块的需求选择不同的框架
重要提示
- 始终使用最新稳定版本的 JSON 库,以获取安全补丁和性能改进
- 在处理外部输入的 JSON 数据时,务必注意安全问题
- 对于复杂的 JSON 处理需求,考虑封装统一的工具类
- 在关键性能路径上,进行性能测试以选择最优方案
通过本文介绍的技巧和最佳实践,相信您能够在 Java 项目中更加高效、安全地处理 JSON 数据。选择合适的工具,遵循最佳实践,将使您的代码更加健壮和可维护。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online