json序列化与反序列化

常见的json处理框架

Jackson

Spring 中常用的json处理框架,自动集成在其中。

共有三个核心包,Streaming、Databid、Annotations

Streaming在Jackson-core模块。定义了一些流处理相关的API以及特定的json

Annotations在 jackson-annotations模块,包含注解

Databid 在 jackson-databind 模块,在 Streaming 包的基础上实现了数据绑定,依赖于 Streaming 和 Annotations 包。

通常引入 jackson-databind 包就可以。

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.11.4</version>
</dependency>

当SpringBoot项目中引入以下依赖时不用再引入jackson依赖(内置)

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

ObjectMapper是最常用的类

readValue()进行反序列化,将常见的内容转换为java对象

writeValue()进行序列化操作,将java对象转换为json对象

需要get/set方法

json转对象

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String json = "{\"username\":\"Jack\", \"age\": \"20\"}";

        User user = objectMapper.readValue(json, User.class);
        System.out.println("user = " + user);
    }

json转list

public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String json = "[{\"username\":\"Jack\", \"age\": \"20\"},{\"username\":\"Tom\", \"age\": \"22\"}]";
        List<User> userList = objectMapper.readValue(json, new TypeReference<List<User>>() {});
        userList.forEach(System.out::print);
    }

json转Map

public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String json = "{\"username\":\"Jack\", \"age\": \"20\"}";
        Map<String, Object> userNmp = objectMapper.readValue(json, new TypeReference<Map>() {});
        for (Map.Entry<String, Object> entry : userNmp.entrySet()) {
            System.out.println(entry.getKey() + ":" + entry.getValue());
        }
    }

字段忽略

如果在进行JSON 转 Java对象时,JSON中出现 Java 类中不存在的属性,那么在转换时会遇到com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException异常。

使用objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)配置可以忽略不存在的属性。

   public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        String json = "{\"username\":\"Jack\", \"age\": \"20\",, \"test\": \"test\"}";
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        User user = objectMapper.readValue(json, User.class);
        System.out.println("user = " + user);
    }

日期处理

常用的java.util.Date类或时间类java.time.LocalDateTime类(JDK8),两者在Jackson中的处理略有不同。

ObjectMapper objectMapper = new ObjectMapper();

// 配置日期格式
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

Jackson配置

// 美化输出
mapper.enable(SerializationFeature.INDENT_OUTPUT);
// 允许序列化空的POJO类
// (否则会抛出异常)
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
// 把java.util.Date, Calendar输出为数字(时间戳)
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

// 在遇到未知属性的时候不抛出异常
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// 强制JSON 空字符串("")转换为null对象值:
mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);

// 在JSON中允许C/C++ 样式的注释(非标准,默认禁用)
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
// 允许没有引号的字段名(非标准)
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// 允许单引号(非标准)
mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
// 强制转义非ASCII字符
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
// 将内容包裹为一个JSON属性,属性名由@JsonRootName注解指定
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);

注解配置

  • 属性使用的注解
@JsonProperty("NickName")//序列化后的json字段为NickName 反序列化也有效
private String name;

@JsonIgnore //标注的字段不参与序列化

@JsonGetter("jsonname") //序列化时自定义名字
@JsonSetter("javaname")// 反序列化时的设置 将某个字段反序列化时设置
  • 实体类使用的注解
1//实体类使用的注解,用于序列化的时候忽略指定的一系列属性,或者反序列化的时候忽略未知的属性(没有getter/setter的属性)。
@JsonIgnoreProperties
序列化的时候,@JsonIgnoreProperties({"prop1", "prop2"}),忽略列表中的属性。
反序列化的时候,@JsonIgnoreProperties(ignoreUnknown=true),忽略没有get/set的属性。
    
2//实体类使用的注解,表示该类被忽略。
@JsonIgnoreType    
    
  • 公用注解
1//实体类/属性使用的注解,用于忽略NULL的属性,空的属性或者NULL的类。
@JsonInclude
    
2//实体类/属性使用的注解,在序列化或者反序列化的时候,指定属性格式化日期/时间。
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",
                timezone = "GMT+8")
    private Date birthday;

FastJSON

Alibaba提供的开源库(效率很高)

pom引用

<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.76</version>
</dependency>

常用API

    //把JSON文本parse为JSONObject或者JSONArray
    public static final Object parse(String text);
    //把JSON文本parse成JSONObject
    public static final JSONObject parseObject(String text);
    //把JSON文本parse为JavaBean
    public static final <T> T parseObject(String text, Class<T> clazz);
    //把JSON文本parse成JSONArray
    public static final JSONArray parseArray(String text);
    //把JSON文本parse成JavaBean集合
    public static final <T> List<T> parseArray(String text, Class<T> clazz);
    //将JavaBean序列化为JSON文本
    public static final String toJSONString(Object object);
    //将JavaBean序列化为带格式的JSON文本
    public static final String toJSONString(Object object, boolean prettyFormat);
    //将JavaBean转换为JSONObject或者JSONArray。
    public static final Object toJSON(Object javaObject);

解析示例

  public static void main(String[] args) {
        String userJson = "{\"users\":[{\"name\":\"小白\",\"age\":\"12\"},{\"name\":\"大白\",\"age\":\"22\"}]}";

        //将json字符串转换为jsonObject
        JSONObject parseObject = JSON.parseObject(userJson);
        // 获取json数组对象
        JSONArray usersArray = parseObject.getJSONArray("users");
        for (Object object : usersArray) {
            JSONObject jsonObejct = (JSONObject) object;
            String name = jsonObejct.getString("name");
            String age = jsonObejct.getString("age");
            System.out.println(name + "----" + age);
        }
    }

日期示例

//缺省会转为long		1401370199040
String dateJson = JSON.toJSONString(new Date());
//SerializerFeature.WriteDateUseDateFormat 默认格式
//"2014-05-29 21:36:24"
String dateJson = JSON.toJSONString(new Date(), SerializerFeature.WriteDateUseDateFormat);
//指定日期格式
//"2014-05-29 21:47:00.154"
String dateJson = JSON.toJSONStringWithDateFormat(new Date(), "yyyy-MM-dd HH:mm:ss.SSS");

设置输出null,直接输出是不包括null的

String listJson = JSON.toJSONString(map, SerializerFeature.WriteMapNullValue);

//输出
//{"a":null,"b":1}

GSON

Google的json处理框架

Gson具有三种API:数据绑定API,树模型API,流API

  1. 数据绑定API
    数据绑定API使用属性访问JSON与POJO之间进行转换。GSON使用数据类型适配器处理json数据。类似于XML JAXB解析器
  2. 树模型API
    创建JSON文档的内存树,它构建JSONElement的树。类似于XML DOM解析器。
  3. 流API
    一种低级API,它使用JsonReader和JsonWriter作为离散记号读取和写入 JSON 内容。 这些类将数据读取为JsonTokens。 该 API 具有最低的开销,并且在读/写操作中速度很快。 它类似于 XML 的 Stax 解析器

pom引用

<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.9.0</version>
</dependency>

转换为json

toJson()

    public static void main(String[] args) {
        Map<Integer, String> map = new HashMap<>();
        map.put(1, "a");
        map.put(2, "b");
        map.put(3, "c");

        Gson gson = new Gson();

        String output = gson.toJson(map);

        System.out.println(output);
    }

装换为指定类

fromJson()

    public static void main(String[] args) {
        String json_string = "{\"username\":\"Jack\", \"age\": \"20\"}";

        Gson gson = new Gson();
        
        User user = gson.fromJson(json_string, User.class);

        System.out.println(user);
    }

    @ToString
    @AllArgsConstructor
    class User {
        private String username;
        private String age;
    }

GsonBuilder

配置构建的GsonBuilder 最后使用create()进行使用**此部分挺重要的**

其中的设置参考

  • setFieldNamingPolicy 设置序列字段的命名策略(UPPER_CAMEL_CASE,UPPER_CAMEL_CASE_WITH_SPACES,LOWER_CASE_WITH_UNDERSCORES,LOWER_CASE_WITH_DASHES)
  • addDeserializationExclusionStrategy 设置反序列化时字段采用策略ExclusionStrategy,如反序列化时不要某字段,当然可以采用@Expore代替。
  • excludeFieldsWithoutExposeAnnotation 设置没有@Expore则不序列化和反序列化
  • addSerializationExclusionStrategy 设置序列化时字段采用策略,如序列化时不要某字段,当然可以采用@Expore代替。
  • registerTypeAdapter 为某特定对象设置固定的序列和反序列方式,实现JsonSerializer和JsonDeserializer接口
  • setFieldNamingStrategy 设置字段序列和反序列时名称显示,也可以通过@Serializer代替
  • setPrettyPrinting 设置gson转换后的字符串为一个比较好看的字符串
  • setDateFormat 设置默认Date解析时对应的format格式
  • serializeNulls() 设置打印输出null字段
    public static void main(String[] args) throws UnsupportedEncodingException {
        try (PrintStream prs = new PrintStream(System.out, true, "UTF8")) {
            Gson gson = new GsonBuilder()
                    // 配置Gson在序列化和反序列化期间将特定的命名策略应用于对象的字段。
                    // 字段命名策略设置为FieldNamingPolicy.UPPER_CAMEL_CASE: 确保Java字段名称的第一个“字母”在序列化为其JSON形式时大写
                    .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
                    .create();

            User user = new User("Jack", 20);
            gson.toJson(user, prs);
        }
    }

    @ToString
    @AllArgsConstructor
    static
    class User {
        private String username;
        private Integer age;
    }

将json数据写入到json文件

这个写法是覆写,如果要使用追加需要调整输出流

public static void main(String[] args) throws IOException {
    String filePath = "src/main/resources/users.json";

    try (FileOutputStream fos = new FileOutputStream(filePath);
         OutputStreamWriter isr = new OutputStreamWriter(fos, StandardCharsets.UTF_8)) {

        Gson gson = new Gson();

        User user1 = new User("Jack", 23);
        User user2 = new User("Jon", 22);
        User user3 = new User("Tom", 33);

        List<User> users = new ArrayList<>();
        users.add(user1);
        users.add(user2);
        users.add(user3);

        gson.toJson(users, isr);
}

JsonParser的一些用法

JsonParser类提供3种方法来提供JSON作为源并将其解析为JsonElements树。

  • JsonElement parse(JsonReader json)–使用JsonReader读取JSON作为令牌流,并从JSON流中返回下一个值作为分析树。
  • JsonElement parse(java.io.Reader json)–使用指定的阅读器读取JSON并将JSON字符串解析为解析树。
  • JsonElement parse(java.lang.String json)–将指定的JSON字符串解析为解析树。

如果指定的文本不是有效的JSON,则这三个方法都将抛出JsonParseException和JsonSyntaxException。

JsonElement, JsonObject 和JsonArray

通过:

JsonElement jsonElement = new JsonParser().parse(json);

将json转为JsonElement后可通过以下方法判断具体类型:(返回值:boolean):

jsonElement.isJsonObject();			//是否为对象
jsonElement.isJsonArray();			//是否为数组
jsonElement.isJsonNull();			//是否为空
jsonElement.isJsonPrimitive();		//是否为java基本类型

然后可以解析为具体类型:

JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonArray jsonArray = jsonElement.getAsJsonArray();

然后对JsonObject通过get方法提取字段

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
 
public class Main 
{
    public static void main(String[] args) throws Exception 
    {
        String json = "{'id': 1001, "
                + "'firstName': 'Lokesh',"
                + "'lastName': 'Gupta',"
                + "'email': 'howtodoinjava@gmail.com'}";
 
        JsonElement jsonElement = new JsonParser().parse(json);
         
        JsonObject jsonObject = jsonElement.getAsJsonObject();
 
        System.out.println( jsonObject.get("id") );
        System.out.println( jsonObject.get("firstName") );
        System.out.println( jsonObject.get("lastName") );
        System.out.println( jsonObject.get("email") );
    }
}

此外还有getAsJsonObject,getAsInt等方法

JsonParser jsonParser = new JsonParser();
JsonElement jsonElement = jsonParser.parse(response);
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonObject data = jsonObject.getAsJsonObject("data");
jsonObject.get("status").getAsInt()

json处理框架对比帖:

Java 解析和处理 json 用哪个开源包最好? - 知乎 (zhihu.com)

找时间验证一下🏃🏃

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

什么都不会的小肆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值