java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java处理JSON技巧

Java处理JSON编程实用技巧和性能优化

作者:熊猫钓鱼>_>

JSON解析是Java Web开发的核心技能,用于服务端和客户端间数据交换,下面这篇文章主要介绍了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日期时间API

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) // 只序列化非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 通用优化原则

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 选择合适的框架

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类中的字段名不一致,导致反序列化失败。

解决方案:

8.2 处理null值

问题:JSON中包含null值,如何控制其序列化和反序列化行为。

解决方案:

8.3 循环引用问题

问题:对象之间存在循环引用,导致序列化时出现StackOverflowError。

解决方案:

8.4 处理复杂嵌套结构

问题:JSON结构复杂,难以直接映射到Java类。

解决方案:

8.5 性能问题

问题:处理大型JSON数据时性能不佳。

解决方案:

9. 总结与建议

选择建议

重要提示

通过本文介绍的技巧和最佳实践,相信您能够在Java项目中更加高效、安全地处理JSON数据。选择合适的工具,遵循最佳实践,将使您的代码更加健壮和可维护。

到此这篇关于Java处理JSON编程实用技巧和性能优化的文章就介绍到这了,更多相关Java处理JSON技巧内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文