Json数据处理工具

young 1,592 2022-01-05

本文中代码中为了使字符串的Json阅读好看,采用了JDK13新增的 Text Blocks

测试代码均在JDK 17 环境中执行,实际使用场景无需使用最新的JDK

同时采用了lombok简化pojo

Jackson

Jackson为spring的默认json序列化工具

相关学习地址:

https://hub.fastgit.org/FasterXML/jackson-docs

https://www.baeldung.com/jackson

https://www.baeldung.com/jackson-annotations

依赖

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

基本使用

Jackson的核心处理对象是ObjectMapper

前置对象和初始化

ObjectMapper objectMapper = new ObjectMapper();

@AllArgsConstructor
@NoArgsConstructor
@Data
public static class TestVo{
    private String name;
    private int age;
    private Date time;
}

对象与json字符串互转

@Test
    public void test_object() throws JsonProcessingException {
        TestVo vo = new TestVo("young", 20, new Date());
        System.out.println(objectMapper.writeValueAsString(vo));
        // {"name":"young","age":20,"time":1634723171329}

        String jsonStr = """
            {
                "name":"young",
                "age":20,
                "time":1634722851440
            }
            """;
        System.out.println(objectMapper.readValue(jsonStr, TestVo.class));
        // TestJackson.TestVo(name=young, age=20, time=Wed Oct 20 17:40:51 CST 2021)
    }

集合与json字符串互转

@Test
public void test_collection() throws JsonProcessingException {
   List<TestVo> collect = IntStream.rangeClosed(1, 5)
         .mapToObj(e -> new TestVo(RandomStringUtils.randomAlphabetic(5, 10), e, new Date()))
         .collect(Collectors.toList());
   String jsonStr = objectMapper.writeValueAsString(collect);
   System.out.println(jsonStr);
    // [{"name":"lPpvlLqfz","age":1,"time":1634723691263},{"name":"oMmvjF","age":2,"time":1634723691263},{"name":"TwVcLW","age":3,"time":1634723691263},{"name":"pjbcZ","age":4,"time":1634723691263},{"name":"SznBEwCz","age":5,"time":1634723691263}]
   List<TestVo> testVos = objectMapper.readValue(jsonStr, new TypeReference<List<TestVo>>() {});
   System.out.println(testVos);
    // [TestJackson.TestVo(name=lPpvlLqfz, age=1, time=Wed Oct 20 17:54:51 CST 2021), TestJackson.TestVo(name=oMmvjF, age=2, time=Wed Oct 20 17:54:51 CST 2021), TestJackson.TestVo(name=TwVcLW, age=3, time=Wed Oct 20 17:54:51 CST 2021), TestJackson.TestVo(name=pjbcZ, age=4, time=Wed Oct 20 17:54:51 CST 2021), TestJackson.TestVo(name=SznBEwCz, age=5, time=Wed Oct 20 17:54:51 CST 2021)]
}

json对象操作

@Test
	public void test_jsonObject() throws JsonProcessingException {
		String json = """
				{
				    "name":"young",
				    "age":20,
				    "addressInfoList":
				        [
				            {
				                "address":"a"
				            },{
				                "address":"b"
				            }
				        ]
				}
				""";
		JsonNode jsonNode = objectMapper.readTree(json);
		System.out.println(jsonNode.get("name").asText());
		System.out.println(jsonNode.get("age").asInt());
		JsonNode addressInfoList = jsonNode.get("addressInfoList");
		Iterator<JsonNode> elements = addressInfoList.elements();
		while (elements.hasNext()) {
			System.out.println(elements.next().get("address").asText());
		}
	}

常用全局配置

输出格式化

默认情况下,json的输出是没有缩进的,可以通过配置进行开启,以下两种方法任选一个即可

objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
@Test
public void test_INDENT_OUTPUT() throws JsonProcessingException {
    TestVo vo = new TestVo("young", 20, new Date());
    ObjectMapper om = new ObjectMapper();
    om.enable(SerializationFeature.INDENT_OUTPUT);
    System.out.println(om.writeValueAsString(vo));
    /*
        {
          "name" : "young",
          "age" : 20,
          "time" : 1641353231867
        }
     */
}

禁用未知属性错误

反序列化时,如果遇到未知的属性(没有属性,没有setter,没有handler处理)就会抛出异常UnrecognizedPropertyException

@Data
public static class TestVo2{
    private String name ;

}

@Test
public void test_UnrecognizedProperty() throws JsonProcessingException {
   String json = """
           {
               "name":"young",
               "age":15
           }
           """;

    TestVo2 s = objectMapper.readValue(json,TestVo2.class);
    System.out.println(s);
}

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "age" (class com.example.TestJackson$TestVo2), not marked as ignorable (one known property: "name"])
 at [Source: (String)"{
    "name":"young",
    "age":15
}
"; line: 3, column: 13] (through reference chain: com.example.TestJackson$TestVo2["age"])

可以通过以下代码进行禁用

objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
@Test
public void test_UnrecognizedProperty() throws JsonProcessingException {
   String json = """
           {
               "name":"young",
               "age":15
           }
           """;

    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    TestVo2 s = objectMapper.readValue(json,TestVo2.class);
    System.out.println(s);
    // TestJackson.TestVo2(name=young)
}

允许序列化空对象

Jackson在执行序列化操作时,默认的字段属性发现规则是,所有被public修饰的字段、所有被public修饰的getter。没有可序列化的属性时,就会抛出异常InvalidDefinitionException: No serializer found for class...

public static class TestVo2{
    private String name = "young";

}

@Test
public void test_EmptyBean() throws JsonProcessingException {
    TestVo2 testVo2 = new TestVo2();
    String s = objectMapper.writeValueAsString(testVo2);
    System.out.println(s);
}

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.example.TestJackson$TestVo2 and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

可以通过以下代码进行禁用

objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
public static class TestVo2{
    private String name = "young";

}

@Test
public void test_EmptyBean() throws JsonProcessingException {
    TestVo2 testVo2 = new TestVo2();
    objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
    String s = objectMapper.writeValueAsString(testVo2);
    System.out.println(s);
    // {}
}

将空字符串反序列为null POJO

默认情况下,空字符串不能反序列化为null对象,会抛出异常

@Data
public static class TestVo2{
    private String name ;

}

@Test
public void test_EmptyString() throws JsonProcessingException {
    String json = """
            {
                "aaa":""
            }
            """;
    Map<String,TestVo2> map = objectMapper.readValue(json, new TypeReference<Map<String,TestVo2>>() {
    });
    System.out.println(map);
}

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot coerce empty String ("") to `com.example.TestJackson$TestVo2` value (but could if coercion was enabled using `CoercionConfig`)
 at [Source: (String)"{
    "aaa":""
}
"; line: 2, column: 11] (through reference chain: java.util.LinkedHashMap["aaa"])

可以通过以下代码进行禁用

objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
@Test
public void test_EmptyString() throws JsonProcessingException {
    String json = """
            {
                "aaa":""
            }
            """;
    objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    Map<String,TestVo2> map = objectMapper.readValue(json, new TypeReference<Map<String,TestVo2>>() {
    });
    System.out.println(map);
    // {aaa=null}
}

常用注解

@JsonIgnore

作用在字段上,使jackson在序列化与反序列化时忽略该属性

@Data
public static class TestVo3{
    private String name;
    @JsonIgnore
    private Date date;
}

@Test
public void test_JsonIgnore() throws JsonProcessingException {
    TestVo3 testVo3 = new TestVo3();
    testVo3.setDate(new Date());
    testVo3.setName("hahaha");
    String s = objectMapper.writeValueAsString(testVo3);
    System.out.println(s);
	// {"name":"hahaha"}
    
    String json = """
            {
                "name":"hahaha",
                "date":"1641353231867"
            }
            """;
    TestVo3 value = objectMapper.readValue(json, TestVo3.class);
    System.out.println(value);
    // TestJackson.TestVo3(name=hahaha, date=null)
}

@JsonProperty

作用于类上,可以忽略指定属性的序列化与反序列化,如

@JsonIgnoreProperties({"name","age","title"})

也可以注明过滤掉未知的属性,如

@JsonIgnoreProperties(ignoreUnknown=true)
@JsonIgnoreProperties(value = {"name"})
@Data
public static class TestVo3{
    private String name;
    private Date date;
}

@Test
public void test_JsonProperty() throws JsonProcessingException {
    TestVo3 testVo3 = new TestVo3();
    testVo3.setDate(new Date());
    testVo3.setName("hahaha");
    String s = objectMapper.writeValueAsString(testVo3);
    System.out.println(s);
	// {"date":1641354740292}
    
    String json = """
            {
                "name":"hahaha",
                "date":"1641353231867"
            }
            """;
    TestVo3 value = objectMapper.readValue(json, TestVo3.class);
    System.out.println(value);
    // TestJackson.TestVo3(name=null, date=Wed Jan 05 11:27:11 CST 2022)
}

@JsonProperty

作用在字段上,可以将json与实体中的字段进行映射,如

@Data
public static class TestVo3{
    @JsonProperty("userName")
    private String name;
    private Date date;
}

@Test
public void test_JsonProperty() throws JsonProcessingException {
    TestVo3 testVo3 = new TestVo3();
    testVo3.setDate(new Date());
    testVo3.setName("hahaha");
    String s = objectMapper.writeValueAsString(testVo3);
    System.out.println(s);
	// {"date":1641354824675,"userName":"hahaha"}
    
    String json = """
            {
                "userName":"hahaha",
                "date":"1641353231867"
            }
            """;
    TestVo3 value = objectMapper.readValue(json, TestVo3.class);
    System.out.println(value);
    // TestJackson.TestVo3(name=hahaha, date=Wed Jan 05 11:27:11 CST 2022)
}

@JsonFormat

作用为字段上,在jackson进行序列化时对字段值进行格式化,如

@Data
public static class TestVo3{
    @JsonProperty("userName")
    private String name;
    @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss",timezone = "GMT+8")
    private Date date;
}

@Test
public void test_JsonFormat() throws JsonProcessingException {
    TestVo3 testVo3 = new TestVo3();
    testVo3.setDate(new Date());
    testVo3.setName("hahaha");
    String s = objectMapper.writeValueAsString(testVo3);
    System.out.println(s);
    // {"date":"2022-01-05 11-55-49","userName":"hahaha"}
}    

@JsonDeserialize

设置类或字段的反序列化操作

创建反序列化处理器

public class TestJsonDeserializer extends JsonDeserializer {
    @Override
    public Object deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String text = jsonParser.getText();
        if (StringUtils.isNotBlank(text)){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                return simpleDateFormat.parse(text);
            } catch (ParseException e) {
                e.printStackTrace();
                return null;
            }
        }
        return null;
    }
}

在字段上标注要使用的反序列化处理器

@Data
public static class TestVo3{

    private String name;
    @JsonDeserialize(using = TestJsonDeserializer.class)
    private Date date;
}

调用readValue

@Test
public void test_JsonDeserialize() throws JsonProcessingException {
    String json = """
            {
                "name":"hahaha",
                "date":"2000-10-01 10:00:00"
            }
            """;
    TestVo3 value = objectMapper.readValue(json, TestVo3.class);
    System.out.println(value);
    // TestJackson.TestVo3(name=hahaha, date=Sun Oct 01 10:00:00 CST 2000)
}

@JsonSerialize

设置类或字段的自定义序列化操作,与反序列化使用方法类似

Gson

Google提供的用于处理json序列化和反序列化的工具

官网

github

依赖

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

创建实例

创建Gson对象有两种方式

Gson gson = new Gson();
GsonBuilder builder = new GsonBuilder();
Gson gson = build.create();

对象序列化与反序列化

定义一个对象

@Data
@AllArgsConstructor
@NoArgsConstructor
static class TestVo{
    private String name;
    private int age;
    private String birth;
}
Gson gson = new Gson();
TestVo vo = new TestVo("young", 10, LocalDate.now().toString());
String json = gson.toJson(vo);
// {"name":"young","age":10,"birth":"2022-05-18"}
System.out.println(json);
TestVo testVo = gson.fromJson(json, TestVo.class);
// TestVo(name=young, age=10, birth=2022-05-18)
System.out.println(testVo);

格式化输出

GsonBuilder builder = new GsonBuilder();
Gson gson = builder.setPrettyPrinting().create();
TestVo vo = new TestVo("young", 10, LocalDate.now().toString());
String json = gson.toJson(vo);
System.out.println(json);
{
  "name": "young",
  "age": 10,
  "birth": "2022-05-18"
}

数组

[
    {
      "name": "Alex",
      "id": 1
    },
    {
      "name": "Brian",
      "id": 2
    },
    {
      "name": "Charles",
      "id": 3
    }
]
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
    private String name;
    private Integer id;
}
User[] users = new Gson().fromJson(jsonArr, User[].class);
for (User user : users) {
    System.out.println(user);
}
List<User> userList = new Gson().fromJson(jsonArr, new TypeToken<List<User>>(){}.getType());
for (User user : userList) {
    System.out.println(user);
}

Null值处理

Gson默认会忽略空对象字段,如需让Json输入null字段,需进行设置

Gson gson = new GsonBuilder().serializeNull().create();

版本支持

@Since注解:表示属性从哪个版本开始支持

@Until注解:表示属性从哪个版本开始移除

@Data
@AllArgsConstructor
@NoArgsConstructor
static class TestVo{
    @Since(1.0)
    private String name;
    @Since(1.1)
    private int age;
    @Since(1.2)
    @Until(1.4)
    private String birth;
}

序列化

Gson gson = new GsonBuilder().setVersion(1.0).create();
TestVo vo = new TestVo("young", 10, LocalDate.now().toString());
// {"name":"young"}
System.out.println(gson.toJson(vo));

gson = new GsonBuilder().setVersion(1.1).create();
// {"name":"young","age":10}
System.out.println(gson.toJson(vo));

gson = new GsonBuilder().setVersion(1.2).create();
// {"name":"young","age":10,"birth":"2022-05-18"}
System.out.println(gson.toJson(vo));

gson = new GsonBuilder().setVersion(1.3).create();
// {"name":"young","age":10,"birth":"2022-05-18"}
System.out.println(gson.toJson(vo));

gson = new GsonBuilder().setVersion(1.4).create();
// {"name":"young","age":10}
System.out.println(gson.toJson(vo));

反序列化

Gson gson = new GsonBuilder().setVersion(1.3).create();
// {"name":"young","age":10,"birth":"2022-05-18"}
String json = gson.toJson(vo);
gson = new GsonBuilder().setVersion(1.0).create();
// TestVo(name=young, age=0, birth=null)
System.out.println(gson.fromJson(json,TestVo.class));

字段名映射

@SerializedName

  • value:序列化或反序列化是所需的字段名称
  • alternate:反序列化时字段的代替名称,如果有多个字段匹配一个属性,则Gson将使用最后处理的那个
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
    @SerializedName(value = "newName",alternate = {"name1","name2"})
    private String name;
    @SerializedName(value = "newId",alternate = {"id1","id2"})
    private Integer id;
}
User young = new User("young", 1);
Gson gson = new Gson();
// {"newName":"young","newId":1}
System.out.println(gson.toJson(young));

String json = "{\"name2\":\"young\",\"id1\":10}";
// User(name=young, id=10)
System.out.println(gson.fromJson(json, User.class));

json = "{\"name2\":\"young\",\"newId\":5,\"id1\":10}";
// User(name=young, id=10)
System.out.println(gson.fromJson(json, User.class));

json = "{\"name2\":\"young\",\"id1\":10,\"newId\":5}";
// User(name=young, id=5)
System.out.println(gson.fromJson(json, User.class));

排除或忽略字段

@Expose

@Expose注解可以用于指定序列化或反序列化时是否需要进行排除

  • serialize:序列化时是否包含该字段,true为包含
  • deserialize:反序列化是是否包含该字段,true为包含

同时需要开启该注解,开启后,未标记该标签的字段不会被序列化和反序列化

@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
    @Expose(serialize = false)
    private String name;
    private Integer id;
}
User young = new User("young", 1);
// {"name":"young","id":1}
System.out.println(new Gson().toJson(young));
// {}
System.out.println(new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create().toJson(young));

transient关键字

给属性增加transient关键字修饰,则该字段既不参与序列化也不参与反序列化

根据修饰符排除

excludeFieldsWithModifiers()方法可以排除指定修饰符的字段

new GsonBuilder().excludeFieldsWithModifiers(Modifier.STATIC).create();

自定义排除策略

创建自定义排除策略的类,并且实现ExclusionStrategy接口

// 自定义注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GsonExclude {
}

// 自定义排除策略
public class MyExclusionStrategy implements ExclusionStrategy {
    @Override
    public boolean shouldSkipField(FieldAttributes f) {
        return f.getAnnotation(GsonExclude.class)!=null;
    }

    @Override
    public boolean shouldSkipClass(Class<?> clazz) {
        return clazz.isAnnotationPresent(GsonExclude.class);
    }
}

当shouldSkipField或shouldSkipClass任一条件满足时,序列化和反序列化时将对属性进行排除

@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
    @GsonExclude
    private String name;
    private Integer id;
}

@Test
public void testExclusionStrategy(){
    Gson gson = new GsonBuilder().setExclusionStrategies(new MyExclusionStrategy()).create();
  	// {"id":2}
    System.out.println(gson.toJson(new User("young", 2)));
}

GsonBuilder

PrettyPrinting 格式化JSON

FieldNamingPolicy 命名标准

在序列化时对JSON字段名称提供集中标准命名约定

如果使用了@SerializedName,那么@SerializedName对应的字段将覆盖FieldNamingPolicy

  • FieldNamingPolicy.IDENTITY:默认策略,字段名称不变
  • FieldNamingPolicy.LOWER_CASE_WITH_DASHES:将Java字段名称从驼峰大小写形式改为小写的字段名称,每个单词之间用破折号(-)分隔
  • FieldNamingPolicy.LOWER_CASE_WITH_DOTS:将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用点(.)分隔
  • FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES:将Java字段名称从其驼峰大小写形式修改为小写的字段名称,其中每个单词都用下划线(_)分隔
  • FieldNamingPolicy.UPPER_CAMEL_CASE:确保序列化为JSON格式的Java字段名称的第一个“字母”大写
  • FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES:确保在将Java字段名称的第一个“字母”序列化为JSON格式时将其大写,并且单词之间将使用空格分隔

serializeNulls()空值的序列化

setExclusionStrategies设置自定义排除策略

setLenient()宽松的JSON语法规则

如果JSON违反结构规则之一,它将抛出MalformedJsonException。如果我们将lenient设置为true,则它将忽视某些违规行为,并尝试读取格式不正确的JSON

自定义序列化及反序列化操作

自定义序列化

需实现JsonSerializer接口,然后注册到GsonBuilder中

例如将Boolean类型序列化时转换为0和1

public class MyJsonSerializer implements JsonSerializer<Boolean> {
    @Override
    public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
        if (src){
            return new JsonPrimitive(1);
        }else {
            return new JsonPrimitive(0);
        }
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
static class User {
    private String name;
    private Integer id;
    private Boolean flag;
}

@Test
public void testJsonSerializer(){
    Gson gson = new GsonBuilder().registerTypeAdapter(Boolean.class, new MyJsonSerializer()).create();
  // {"name":"name","id":20,"flag":1}
    System.out.println(gson.toJson(new User("name", 20, true)));
}

自定义反序列化

需实现JsonDeserializer接口,然后注册到GsonBuilder中

@Data
@AllArgsConstructor
@NoArgsConstructor
static class TestVo{
    private String name;
    private int age;
    private LocalDate birth;
}
public class MyJsonDeserializer implements JsonDeserializer<GsonTest.TestVo> {
    @Override
    public GsonTest.TestVo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        LocalDate localDate = LocalDate.of(
                jsonObject.get("year").getAsInt(),
                jsonObject.get("month").getAsInt(),
                jsonObject.get("day").getAsInt());
        return new GsonTest.TestVo(
                jsonObject.get("name").getAsString(),
                jsonObject.get("age").getAsInt(),
                localDate);
    }
}
@Test
public void testDeserializer(){
    String json = "{\"name\":\"hahaha\",\"age\":50,\"year\":2022,\"month\":5,\"day\":18}";
    Gson gson = new GsonBuilder().registerTypeAdapter(TestVo.class, new MyJsonDeserializer()).create();
  // TestVo(name=hahaha, age=50, birth=2022-05-18)
    System.out.println(gson.fromJson(json, TestVo.class));
}

解析json字符串

使用JsonParser

https://github.com/google/gson/blob/master/gson/src/test/java/com/google/gson/JsonParserTest.java

Fastjson(todo)

fastjson是阿里巴巴开源的json处理工具

依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.79</version>
</dependency>

基本使用

对象和json字符串互转

@AllArgsConstructor
@NoArgsConstructor
@Data
public static class TestVo {
    private String name;
    private int age;
    private Date time;
}

@Test
public void test_Object(){
    TestVo testVo = new TestVo("yonug", 28, new Date());
    String s = JSONObject.toJSONString(testVo);
    System.out.println(s);
	// {"age":28,"name":"yonug","time":1641360720757}
    
    String json = """
            {
                "age":28,
                "name":"yonug",
                "time":1641360602911
            }
            """;
    TestVo vo = JSONObject.parseObject(json, TestVo.class);
    System.out.println(vo);
    // TestFastJson.TestVo(name=yonug, age=28, time=Wed Jan 05 13:30:02 CST 2022)
}

集合和json字符串互转

@Test
public void test_Array(){
    List<TestVo> collect = IntStream.rangeClosed(1, 5)
            .mapToObj(e -> new TestVo(RandomStringUtils.randomAlphabetic(5, 10), e, new Date()))
            .collect(Collectors.toList());
    String s = JSONArray.toJSONString(collect);
    System.out.println(s);
	// [{"age":1,"name":"iLuef","time":1641360921164},{"age":2,"name":"Jutus","time":1641360921164},{"age":3,"name":"XaIxF","time":1641360921164},{"age":4,"name":"BMDhp","time":1641360921164},{"age":5,"name":"toYORjcow","time":1641360921164}]

    List<TestVo> testVos = JSONArray.parseArray(s, TestVo.class);
    System.out.println(testVos);
	// [TestFastJson.TestVo(name=iLuef, age=1, time=Wed Jan 05 13:35:21 CST 2022), TestFastJson.TestVo(name=Jutus, age=2, time=Wed Jan 05 13:35:21 CST 2022), TestFastJson.TestVo(name=XaIxF, age=3, time=Wed Jan 05 13:35:21 CST 2022), TestFastJson.TestVo(name=BMDhp, age=4, time=Wed Jan 05 13:35:21 CST 2022), TestFastJson.TestVo(name=toYORjcow, age=5, time=Wed Jan 05 13:35:21 CST 2022)]
}

json对象操作

@Test
public void test_jsonObject(){
    String json = """
            {
                "name":"young",
                "age":20,
                "addressInfoList":
                    [
                        {
                            "address":"a"
                        },{
                            "address":"b"
                        }
                    ]
			}
            """;
    JSONObject jsonObject = JSONObject.parseObject(json);
    String name = jsonObject.getString("name"); 	// young
    int age = jsonObject.getIntValue("age");		// 28
    JSONArray addressInfoList = jsonObject.getJSONArray("addressInfoList");
    for (int i = 0; i < addressInfoList.size(); i++) {
        JSONObject object = addressInfoList.getJSONObject(i);
        String address = object.getString("address"); // a  b
    }
}

常用注解

@JSONField

可以配置在属性上

@JSONField(ordinal=1)//配置序列化的字段顺序(1.1.42版本之后才支持)

@JSONField(serialize=false) //是否参与序列化:该字段不输出  但是如果加了final,这个字段就无法被过滤

@JSONField(derialize=false) //是否参与反序列化:该字段不输出  但是如果加了final,这个字段就无法被过滤 

@JSONField(format="yyyy-MM-dd HH:mm:ss") //日期按照指定格式序列化

@JSONField(name="别名");//使用字段别名

@JSONField(serialzeFeatures={SerialzeFeatures属性});//序列化规则

@JSONField(parseFeatures={Features属性});//反序列化规则

SerializerFeature属性

public enum SerializerFeature {
    /**
     * 输出key时是否使用双引号,默认为true
     */
    QuoteFieldNames,
    /**
     * 使用单引号而不是双引号,默认为false
     */
    UseSingleQuotes,
    /**
     * 是否输出值为null的字段,默认为false
     */
    WriteMapNullValue,
    /**
     * 用枚举toString()值输出
     */
    WriteEnumUsingToString,
    /**
     * 用枚举name()输出
     */
    WriteEnumUsingName,
    /**
     * Date使用ISO8601格式输出,默认为false
     */
    UseISO8601DateFormat,
    /**
     * @since 1.1
     * List字段如果为null,输出为[],而非null
     */
    WriteNullListAsEmpty,
    /**
     * @since 1.1
     * 字符类型字段如果为null,输出为"",而非null
     */
    WriteNullStringAsEmpty,
    /**
     * @since 1.1
     * 数值字段如果为null,输出为0,而非null
     */
    WriteNullNumberAsZero,
    /**
     * @since 1.1
     * Boolean字段如果为null,输出为false,而非null
     */
    WriteNullBooleanAsFalse,
    /**
     * @since 1.1
     * 如果是true,类中的Get方法对应的Field是transient,序列化时将会被忽略。默认为true
     */
    SkipTransientField,
    /**
     * @since 1.1
     * 按字段名称排序后输出。默认为false
     */
    SortField,
    /**
     * @since 1.1.1
     * 把\t做转义输出,默认为false(不推荐,已删除)
     */
    @Deprecated
    WriteTabAsSpecial,
    /**
     * @since 1.1.2
     * 结果是否格式化,默认为false
     */
    PrettyFormat,
    /**
     * @since 1.1.2
     * 序列化时写入类型信息,默认为false。反序列化时需用到
     */
    WriteClassName,
    /**
     * @since 1.1.6
     * 消除对同一对象循环引用的问题,默认为false
     */
    DisableCircularReferenceDetect,
    /**
     * @since 1.1.9
     * 对斜杠"/"进行转义
     */
    WriteSlashAsSpecial,
    /**
     * @since 1.1.10
     * 将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6,默认为false
     */
    BrowserCompatible,
    /**
     * @since 1.1.14
     * 全局修改日期格式,默认为false。JSON.DEFFAULT_DATE_FORMAT = “yyyy-MM-dd”;JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
     */
    WriteDateUseDateFormat,
    /**
     * @since 1.1.15
     */
    NotWriteRootClassName,
    /**
     * @since 1.1.19
     * 一个对象的字符串属性中如果有特殊字符如双引号,将会在转成json时带有反斜杠转移符。如果不需要转义,可以使用这个属性。默认为false
     */
    DisableCheckSpecialChar,
    /**
     * @since 1.1.35
     * 将对象转为array输出
     */
    BeanToArray,
    /**
     * @since 1.1.37
     */
    WriteNonStringKeyAsString,   
    /**
     * @since 1.1.42
     */
    NotWriteDefaultValue,    
    /**
     * @since 1.2.6
     */
    BrowserSecure,    
    /**
     * @since 1.2.7
     */
    IgnoreNonFieldGetter,   
    /**
     * @since 1.2.9
     */
    WriteNonStringValueAsString,    
    /**
     * @since 1.2.11
     */
    IgnoreErrorGetter;

}

Feature属性

public enum Feature {
    /**
     * 这个特性,决定了解析器是否将自动关闭那些不属于parser自己的输入源。 
     * 如果禁止,则调用应用不得不分别去关闭那些被用来创建parser的基础输入流InputStream和reader;
     * 如果允许,parser只要自己需要获取closed方法(当遇到输入流结束,或者parser自己调用 JsonParder#close方法),就会处理流关闭。
     * 注意:这个属性默认是true,即允许自动关闭流
     */
    AutoCloseSource,
    /**
     * 该特性决定parser将是否允许解析使用Java/C++ 样式的注释(包括'/'+'*' 和'//' 变量)。 
     * 由于JSON标准说明书上面没有提到注释是否是合法的组成,所以这是一个非标准的特性;尽管如此,这个特性还是被广泛地使用。
     * 注意:该属性默认是false,因此必须显式允许,即通过JsonParser.Feature.ALLOW_COMMENTS 配置为true。
     */
    AllowComment,
    /**
     * 这个特性决定parser是否将允许使用非双引号属性名字, (这种形式在Javascript中被允许,但是JSON标准说明书中没有)。
     * 注意:由于JSON标准上需要为属性名称使用双引号,所以这也是一个非标准特性,默认是false的。
     * 同样,需要设置JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES为true,打开该特性。
     */
    AllowUnQuotedFieldNames,
    /**
     * 该特性决定parser是否允许单引号来包住属性名称和字符串值。
     * 注意:默认下,该属性也是关闭的。需要设置JsonParser.Feature.ALLOW_SINGLE_QUOTES为true
     */
    AllowSingleQuotes,
    /**
     * 该特性决定JSON对象属性名称是否可以被String#intern 规范化表示。如果允许,则JSON所有的属性名将会 intern() ;
     * 如果不设置,则不会规范化,默认下,该属性是开放的。此外,必须设置CANONICALIZE_FIELD_NAMES为true
     * 关于intern方法作用:当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串 (该对象由 equals(Object) 方法确定),则返回池中的字符串。
     * 否则,将此 String 对象添加到池中, 并且返回此 String 对象的引用。
     */
    InternFieldNames,
    /**
     * 这个设置为true则遇到字符串符合ISO8601格式的日期时,会直接转换成日期类。
     */
    AllowISO8601DateFormat,
    /**
     * 允许多重逗号,如果设为true,则遇到多个逗号会直接跳过。
     * {"a":1,,,"b":2}
     */
    AllowArbitraryCommas,
    /**
     * 这个设置为true则用BigDecimal类来装载数字,否则用的是double;
     */
    UseBigDecimal,  
    /**
     * @since 1.1.2 
     * 忽略不匹配
     */
    IgnoreNotMatch,
    /**
     * @since 1.1.3
     * 如果你用fastjson序列化的文本,输出的结果是按照fieldName排序输出的,parser时也能利用这个顺序进行优化读取。这种情况下,parser能够获得非常好的性能
     */
    SortFeidFastMatch,  
    /**
     * @since 1.1.3
     * 禁用ASM
     */
    DisableASM, 
    /**
     * @since 1.1.7
     * 禁用循环引用检测
     */
    DisableCircularReferenceDetect,    
    /**
     * @since 1.1.10
     * 对于没有值的字符串属性设置为空串
     */
    InitStringFieldAsEmpty,   
    /**
     * @since 1.1.35
     * 支持数组to对象
     */
    SupportArrayToBean,   
    /**
     * @since 1.2.3
     * 属性保持原来的顺序
     */
    OrderedField,  
    /**
     * @since 1.2.5
     * 禁用特殊字符检查
     */
    DisableSpecialKeyDetect,
    
    /**
     * @since 1.2.9
     * 使用对象数组
     */
    UseObjectArray;

}