Java处理JSON编程实用技巧
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 gson = new Gson(); // Java对象转JSON字符串 User user = new User("张三", 25); String json = gson.toJson(user); System.out.println(json); // {"name":"张三","age":25} // JSON字符串转Java对象 String jsonString = "{\"name\":\"李四\",\"age\":30}"; User parsedUser = gson.fromJson(jsonString, User.class); System.out.println(parsedUser.getName()); // 李四3.1.3 集合类型的序列化与反序列化
// 序列化集合 List<User> userList = Arrays.asList( new User("张三", 25), new User("李四", 30) ); String jsonList = gson.toJson(userList); // 反序列化集合 - 方法1:使用TypeToken Type userListType = new TypeToken<List<User>>(){}.getType(); List<User> parsedList = gson.fromJson(jsonList, userListType); // 反序列化集合 - 方法2:先转为数组再转集合 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() // 序列化null值 .setDateFormat("yyyy-MM-dd HH:mm:ss") // 设置日期格式 .excludeFieldsWithoutExposeAnnotation() // 只序列化有@Expose注解的字段 .registerTypeAdapter(Date.class, new DateSerializer()) // 注册自定义类型适配器 .disableHtmlEscaping() // 禁用HTML转义 .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; // getter和setter方法... } // 注意:使用@Expose需要配合excludeFieldsWithoutExposeAnnotation() Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();3.2.4 处理复杂嵌套对象
// 使用JsonElement处理未知结构的JSON 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> <!-- 可选:处理XML --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.13.0</version> </dependency>4.1.2 基本序列化与反序列化
// 创建ObjectMapper实例 ObjectMapper objectMapper = new ObjectMapper(); // Java对象转JSON字符串 User user = new User("张三", 25); String json = objectMapper.writeValueAsString(user); System.out.println(json); // {"name":"张三","age":25} // JSON字符串转Java对象 String jsonString = "{\"name\":\"李四\",\"age\":30}"; User parsedUser = objectMapper.readValue(jsonString, User.class); System.out.println(parsedUser.getName()); // 李四 // 格式化输出JSON 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 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) // 不序列化null值 .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) // 日期不使用时间戳 .setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")) // 设置日期格式 .registerModule(new JavaTimeModule()); // 支持Java 8日期时间API4.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) // 只序列化非null值 private String email; @JsonInclude(JsonInclude.Include.NON_EMPTY) // 只序列化非空值 private List<String> hobbies; // getter和setter方法... }4.2.4 处理复杂JSON结构
// 使用JsonNode处理未知结构的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); // 转换为JSON字符串 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 基本序列化与反序列化
// Java对象转JSON字符串 User user = new User("张三", 25); String json = JSON.toJSONString(user); System.out.println(json); // {"age":25,"name":"张三"} // JSON字符串转Java对象 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 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, // null字符串输出为"" SerializerFeature.WriteNullNumberAsZero, // null数字输出为0 SerializerFeature.WriteNullBooleanAsFalse, // null布尔值输出为false SerializerFeature.WriteNullListAsEmpty, // null列表输出为[] SerializerFeature.DisableCircularReferenceDetect, // 禁用循环引用检测 SerializerFeature.WriteDateUseDateFormat, // 日期格式化 SerializerFeature.WriteMapNullValue // 输出null值 );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 deserialze(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; // getter和setter方法... }5.2.4 使用JSONObject和JSONArray
// 创建JSONObject JSONObject jsonObject = new JSONObject(); jsonObject.put("name", "张三"); jsonObject.put("age", 25); // 创建嵌套JSONObject JSONObject addressObject = new JSONObject(); addressObject.put("city", "北京"); addressObject.put("district", "朝阳区"); jsonObject.put("address", addressObject); // 创建JSONArray JSONArray hobbiesArray = new JSONArray(); hobbiesArray.add("读书"); hobbiesArray.add("游泳"); jsonObject.put("hobbies", hobbiesArray); // 转换为JSON字符串 String json = jsonObject.toJSONString(); // 解析复杂JSON 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 安全配置
// 禁用AutoType,防止反序列化漏洞 ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 如果需要使用AutoType,建议使用白名单机制 ParserConfig parserConfig = ParserConfig.getGlobalInstance(); parserConfig.addAccept("com.example.model."); // 只允许反序列化指定包下的类 // 或者使用安全的JSONReader JSONReader jsonReader = new JSONReader(new StringReader(jsonString)); jsonReader.config(Feature.SupportAutoType, false);6. 性能优化技巧
6.1 通用优化原则
- 重用对象:避免重复创建JSON解析器实例(Gson、ObjectMapper或JSON),这些实例是线程安全的
- 避免不必要的转换:直接在流上进行操作,减少中间字符串的创建
- 选择合适的解析模式:根据需求选择树模型或流式API
- 优化数据结构:减少不必要的嵌套和冗余字段
- 合理使用缓存:缓存序列化/反序列化的结果
6.2 Gson性能优化
// 1. 重用Gson实例 public class GsonHolder { private static final Gson GSON = new GsonBuilder() .setPrettyPrinting() .create(); public static Gson getGson() { return GSON; } } // 2. 使用TypeAdapter进行高性能序列化/反序列化 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"))); // 3. 避免使用toJsonTree再toJson,直接使用toJson String json = GsonHolder.getGson().toJson(user);6.3 Jackson性能优化
// 1. 重用ObjectMapper实例 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; } } // 2. 使用流式API处理大型JSON // 序列化大型对象到文件 ObjectMapperHolder.getObjectMapper().writeValue(new File("large.json"), largeObject); // 反序列化大型JSON LargeObject largeObject = ObjectMapperHolder.getObjectMapper() .readValue(new File("large.json"), LargeObject.class); // 3. 使用JsonNode高效处理部分字段 JsonNode rootNode = ObjectMapperHolder.getObjectMapper().readTree(jsonString); String neededField = rootNode.get("neededField").asText(); // 4. 使用TypeFactory预构建复杂类型 JavaType listType = ObjectMapperHolder.getObjectMapper().getTypeFactory() .constructCollectionType(List.class, User.class);6.4 Fastjson性能优化
// 1. 使用TypeReference提高泛型反序列化性能 List<User> userList = JSON.parseObject(jsonList, new TypeReference<List<User>>() {}); // 2. 使用JSONB格式(Fastjson 2.0+) byte[] bytes = JSONB.toJSONBBytes(user); User parsedUser = JSONB.parseObject(bytes, User.class); // 3. 自定义序列化过滤器提高性能 PropertyFilter propertyFilter = new PropertyFilter() { @Override public boolean apply(Object object, String name, Object value) { // 只序列化需要的字段 return !"password".equals(name); } }; String json = JSON.toJSONString(user, propertyFilter); // 4. 使用JSONReader处理大型JSON 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 代码组织最佳实践
// 示例:创建统一的JSON工具类 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 错误处理和异常管理
// 优雅处理JSON解析异常 try { User user = JsonUtils.fromJson(jsonString, User.class); // 处理用户对象 } catch (RuntimeException e) { // 记录详细错误信息 log.error("JSON解析失败: {}", jsonString, e); // 友好的错误响应 throw new BusinessException("数据格式错误,请检查输入"); } // 验证JSON格式 try { ObjectMapperHolder.getObjectMapper().readTree(jsonString); // JSON格式有效 } catch (Exception e) { // JSON格式无效 throw new IllegalArgumentException("无效的JSON格式"); }7.4 安全处理
安全提示:处理外部JSON数据时,务必注意安全问题,特别是反序列化操作可能导致远程代码执行漏洞。
// Jackson安全配置 ObjectMapper mapper = new ObjectMapper(); // 禁用外部实体,防止XXE攻击 mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); // 限制反序列化的类 mapper.registerModule(new SimpleModule() .addDeserializer(Object.class, new SafeObjectDeserializer())); // Fastjson安全配置 ParserConfig.getGlobalInstance().setAutoTypeSupport(false); // 使用白名单 ParserConfig.getGlobalInstance().addAccept("com.example.model."); // Gson安全配置 Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new SafeTypeAdapterFactory()) .create();7.5 处理日期时间
// Jackson日期时间处理 ObjectMapper mapper = new ObjectMapper(); // 配置日期格式 mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); // 支持Java 8日期时间API mapper.registerModule(new JavaTimeModule()); mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // Gson日期时间处理 Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd HH:mm:ss") .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeSerializer()) .registerTypeAdapter(LocalDateTime.class, new LocalDateTimeDeserializer()) .create(); // Fastjson日期时间处理 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数据。选择合适的工具,遵循最佳实践,将使您的代码更加健壮和可维护。