9.fastjson和jackjon入门基础

746 阅读15分钟

一、常见的序列化框架

1、kyro: 速度快,序列化后体积小,但是跨语言支持比较复杂。

2、Hessian: 默认支持跨语言,但是效率不高。

3、Protostuff: 速度快,需静态编译

4、Java: 使用方便,可以序列化所有类,但是速度慢,占空间

5、fastjson: 这个是最常用的,序列化成JSON格式,可视化较高,而且最有意思的是它的迭代过程,充斥着和黑客们的斗智斗勇,我们仔细说说这个fastjson

jackson和fastjson并没有使用Java自带的序列化机制,而是使用反射机制,调用get和set方法进行序列化和反序列化

二、fastjson基础

1.添加依赖

  <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2</artifactId>
      <version>2.0.34</version>
  </dependency>
  
  <!-- Sring 5 -->
  <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2-extension-spring5</artifactId>
      <version>2.0.34</version>
  </dependency>
  
  <!-- 或者 -->
  
  <!-- Sring 6 -->
  <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2-extension-spring6</artifactId>
      <version>2.0.34</version>
  </dependency>

2.配置默认JSON解析库

  @Configuration
  public class SpringMVCConfig implements WebMvcConfigurer {
      @Override
      public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
          // 创建FastJson消息转换器
          FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
          // 创建配置对象
          FastJsonConfig config = new FastJsonConfig();
  
          // 配置序列化策略
          config.setWriterFeatures(JSONWriter.Feature.PrettyFormat,
                  JSONWriter.Feature.WriteMapNullValue,
                  JSONWriter.Feature.WriteNullStringAsEmpty);
  
          // 配置字符集
          fastJsonHttpMessageConverter.setDefaultCharset(StandardCharsets.UTF_8);
  
          // 将配置添加到转换器中
          fastJsonHttpMessageConverter.setFastJsonConfig(config);
  
          converters.add(0,fastJsonHttpMessageConverter);
      }
  }

这些配置可以使SpringMVC使用FastJson作为默认的JSON解析库。

SpringMVC统一配置时间返回格式:

  spring:
    mvc:
      format:
        date-time: yyyy-MM-dd HH:mm:ss #fastjson
    jackson:
        time-zone: GMT+8
        date-format: yyyy/MM/dd HH:mm:ss #jackjson
        serialization:
           #关闭jackson 对json做解析
           fail-on-empty-beans: false

3.使用fastjson

fastjson的使用主要是三个对象:

  • JSON
  • JSONObject
  • JSONArray

JSONArrayJSONObject继承JSON

3.1JSON对象

JSON这个类主要用于转换

  • 将Java对象序列化为JSON字符串
  • 将JSON字符串反序列化为Java对象

所以,有三个方法我们用得特别多:

  • parseObject(String text, Class<T> clazz)
  • parseArray(String text, Class<T> clazz)
  • toJSONString(Object object)

一般用法:

  @Test
  public void test1() {
      //创建一个对象
      SysUser sysUser = new SysUser();
      sysUser.setUserName("孙悟空");
      Set<String> permisons = new HashSet<>();
      permisons.add("sys:user:list");
      SysRole sysRole = new SysRole();
      sysRole.setRoleName("普通角色");
      sysRole.setRoleKey("common");
      List<SysRole> sysRoles = new ArrayList<>();
      sysRoles.add(sysRole);
      LoginUser loginUser = new LoginUser(1L, 1L, sysUser, permisons, sysRoles);
      //转成json字符串
      String s = JSON.toJSONString(loginUser);
      System.out.println(s);
  }
  
  @Test
  public void test2() {
      LoginUser loginUser =  JSON.parseObject("{"deptId":1,"permissions":["sys:user:list"],"user":{"admin":false,"params":{},"userName":"孙悟空"},"userId":1,"username":"孙悟空"}\n",LoginUser.class);
      //反序列化
      System.out.println(loginUser);
  }
  

添加功能:

  String s = JSON.toJSONString(loginUser, JSONWriter.Feature.PrettyFormat);

常见功能:

  • JSONWriter.Feature.PrettyFormat 格式化输出json
  • JSONWriter.Feature.NotWriteEmptyArray 数组为空时,不写入json
  • JSONWriter.Feature.WriteNullStringAsEmpty 字符串为空时,json值为 "" , 默认
  • JSONWriter.Feature.WriteNullListAsEmpty list为空时,json值为[],默认
  • JSONWriter.Feature.WriteNullNumberAsZero 数值类型字段为空时,json值为0
  • JSONWriter.Feature.WriteMapNullValue 对象字段值为null,默认不写入json中
  • JSONWriter.Feature.WriteClassName 写入类名

3.2 JSONObject

JSON对象(JSONObject)中的数据都是以key-value形式出现,所以它实现了Map接口:

使用起来也很简单,跟使用Map就没多大的区别(因为它底层实际上就是操作Map),常用的方法:

  • getString(String key)
  • remove(Object key)

3.3 JSONArray

JSONArray则是JSON数组,JSON数组对象中存储的是一个个JSON对象,所以类中的方法主要用于直接操作JSON对象

  • getJSONObject(int index)

4.fastjson注解

4.1@JSONField注解

  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
  public @interface JSONField {
      int ordinal() default 0; //序列化后排序
  
      String name() default ""; // 指定序列化后的名字
  
      String format() default ""; //日期类型的字段格式化,long类型无效
  
      boolean serialize() default true; //是否序列化
  
      boolean deserialize() default true;//是否反序列化
      
      JSONWriter.Feature[] serializeFeatures() default {}; //特性
      //其他省略
  }

使用举例:

  @JSONField(name="token",ordinal = 1)
  private String token;
  
  @JSONField(serialize = false) //不序列化这个字段
  private String name;
  
  @JSONField(format = "yyyy-MM-dd") //格式化日期类型
  private LocalDateTime updateTime;
  
  @JSONField(serializeFeatures = {JSONWriter.Feature.WriteNullBooleanAsFalse}) //添加特性
  public boolean isAccountNonExpired() {}

4.2@JSONType注解

  @JSONType(orders = {"permissions","loginTime","deptId"}) //字段顺序
  public class LoginUser implements UserDetails {}
  
  @JSONType(includes = {"permissions","loginTime","deptId"}) //要序列化的字段
  public class LoginUser implements UserDetails {}
  
  @JSONType(serializeFeatures = {JSONWriter.Feature.WriteNullBooleanAsFalse}) //特性
  public class LoginUser implements UserDetails {}

三、jackson基础

1.引入依赖

  <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
  </dependency>
  

2.jackson常用API

1.对象的序列化和反序列化

  public static void main(String[] args) {
      // 创建Jackson核心对象 ObjectMapper
      ObjectMapper objectMapper = new ObjectMapper();
      Person person = new Person(1,"DT",new Date());
      try {
          String json = objectMapper.writeValueAsString(person);
          System.out.println("json字符串->>>"+json);
          Person person = objectMapper.readValue(json, Person.class);
          System.out.println("java对象->>>"+person);
      } catch (JsonProcessingException e) {
          e.printStackTrace();
      }
  }

2.数组的序列化和反序列化

  public static void main(String[] args) throws JsonProcessingException {
      //list对象转json字符串
      ObjectMapper objectMapper = new ObjectMapper();
      List<Person> personList = new ArrayList<>();
      personList.add(new Person(1,"DT",new Date()));
      personList.add(new Person(2,"DT1",new Date()));
      personList.add(new Person(3,"DT2",new Date()));
      String json = objectMapper.writeValueAsString(personList);
      System.out.println("json->>>"+json);
      
      // 将JSON数组转换为array对象
      // 方式1
      Person[] pp1 = mapper.readValue(json, Person[].class);
      for (Person person : pp1) {
          System.out.println(person);
      }
      // 方式2
      List<Person> ppl2 = Arrays.asList(mapper.readValue(json, Person[].class));
      ppl2.stream().forEach(System.out::println);
      // 方式3
      List<Person> pp3 = mapper.readValue(json, new TypeReference<List<Person>>() {});
      pp3.stream().forEach(System.out::println);
  }

3.Jackson注解

Jackson JSON工具包包含一组Java注解,可以使用这些注解来设置将JSON读入对象的方式或从对象生成什么JSON的方式。 此Jackson注解教程介绍了如何使用Jackson的注解。

下面是一些常用的注解:

注解用法
@JsonProperty用于属性,把属性的名称序列化时转换为另外一个名称。示例: @JsonProperty("birth_ d ate") private Date birthDate;
@JsonFormat用于属性或者方法,把属性的格式序列化时转换成指定的格式。示例: @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm") public Date getBirthDate()
@JsonPropertyOrder用于类, 指定属性在序列化时 json 中的顺序 , 示例: @JsonPropertyOrder({ "birth_Date", "name" }) public class Person
@JsonCreator用于构造方法,和 @JsonProperty 配合使用,适用有参数的构造方法。 示例: @JsonCreator public Person(@JsonProperty("name")String name) {…}
@JsonAnySetter用于属性或者方法,设置未反序列化的属性名和值作为键值存储到 map 中 @JsonAnySetter public void set(String key, Object value) { map.put(key, value); }
@JsonAnyGetter用于方法 ,获取所有未序列化的属性 public Map<String, Object> any() { return map; }

下面是一些注解的详细说明。

3.1Read + Write注解

Jackson包含一组注解,这些注解会影响从JSON读取Java对象以及将Java对象写入JSON。 我将这些注解称为“读+写注解”。 以下各节将更详细地介绍Jackson的读写注解。

1、@JsonIgnore

Jackson注解@JsonIgnore用于告诉Jackson忽略Java对象的某个属性(字段)。 在将JSON读取到Java对象中以及将Java对象写入JSON时,都将忽略该属性。

这是使用@JsonIgnore注解的示例:

  import com.fasterxml.jackson.annotation.JsonIgnore;
  
  public class PersonIgnore {
  
      @JsonIgnore
      public long  personId = 0;
  
      public String name = null;
  }

在上面的类中,不会从JSON读取或写入JSON属性personId。

2、@JsonIgnoreProperties

@JsonIgnoreProperties Jackson注解用于指定要忽略的类的属性列表。 @JsonIgnoreProperties注解放置在类声明上方,而不是要忽略的各个属性(字段)上方。

这是如何使用@JsonIgnoreProperties注解的示例:

  import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
  
  @JsonIgnoreProperties({"firstName", "lastName"})
  public class PersonIgnoreProperties {
  
      public long   personId = 0;
  
      public String  firstName = null;
      public String  lastName  = null;
  
  }

在此示例中,属性firstName和lastName都将被忽略,因为它们的名称在类声明上方的@JsonIgnoreProperties注解声明内列出。

3、@JsonIgnoreType

@JsonIgnoreType Jackson注解用于将整个类型(类)标记为在使用该类型的任何地方都将被忽略。

这是一个示例,展示如何使用@JsonIgnoreType注解:

  import com.fasterxml.jackson.annotation.JsonIgnoreType;
  
  public class PersonIgnoreType {
  
      @JsonIgnoreType
      public static class Address {
          public String streetName  = null;
          public String houseNumber = null;
          public String zipCode     = null;
          public String city        = null;
          public String country     = null;
      }
  
      public long    personId = 0;
  
      public String  name = null;
  
      public Address address = null;
  }

在上面的示例中,所有Address实例将被忽略。

4、@JsonAutoDetect

Jackson注解@JsonAutoDetect用于告诉Jackson在读写对象时包括非public修饰的属性。

这是一个示例类,展示如何使用@JsonAutoDetect注解:

  import com.fasterxml.jackson.annotation.JsonAutoDetect;
  
  @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
  public class PersonAutoDetect {
  
      private long  personId = 123;
      public String name     = null;
  
  }

JsonAutoDetect.Visibility类包含与Java中的可见性级别匹配的常量,表示ANY,DEFAULT,NON_PRIVATE,NONE,PROTECTED_AND_PRIVATE和PUBLIC_ONLY。

3.2Read注解

Jackson包含一组注解,这些注解仅影响Jackson将JSON解析为对象的方式-意味着它们影响Jackson对JSON的读取。 我称这些为“读注解”。 以下各节介绍了Jackson的读注解。

1、@JsonSetter

Jackson注解@JsonSetter用于告诉Jackson,当将JSON读入对象时,应将此setter方法的名称与JSON数据中的属性名称匹配。 如果Java类内部使用的属性名称与JSON文件中使用的属性名称不同,这个注解就很有用了。

以下Person类用personId名称对应JSON中名为id的字段:

  public class Person {
  
      private long   personId = 0;
      private String name     = null;
  
      public long getPersonId() { return this.personId; }
      public void setPersonId(long personId) { this.personId = personId; }
  
      public String getName() { return name; }
      public void setName(String name) { this.name = name; }
  }

但是在此JSON对象中,使用名称id代替personId:

 {
   "id"   : 1234,
   "name" : "John"
 }

Jackson无法将id属性从JSON对象映射到Java类的personId字段。

@JsonSetter注解指示Jackson为给定的JSON字段使用setter方法。 在我们的示例中,我们在setPersonId()方法上方添加@JsonSetter注解。

这是添加@JsonSetter注解的实例:

 public class Person {
 
     private long   personId = 0;
     private String name     = null;
 
     public long getPersonId() { return this.personId; }
     @JsonSetter("id")
     public void setPersonId(long personId) { this.personId = personId; }
 
     public String getName() { return name; }
     public void setName(String name) { this.name = name; }
 }

@JsonSetter注解中指定的值是要与此setter方法匹配的JSON字段的名称。 在这种情况下,名称为id,因为这是我们要映射到setPersonId()setter方法的JSON对象中字段的名称。

2、@JsonAnySetter

Jackson注解@JsonAnySetter表示Jackson为JSON对象中所有无法识别的字段调用相同的setter方法。 “无法识别”是指尚未映射到Java对象中的属性或设置方法的所有字段。

看一下这个Bag类:

 public class Bag {
 
     private Map<String, Object> properties = new HashMap<>();
 
     public void set(String fieldName, Object value){
         this.properties.put(fieldName, value);
     }
 
     public Object get(String fieldName){
         return this.properties.get(fieldName);
     }
 }

然后查看此JSON对象:

 {
   "id"   : 1234,
   "name" : "John"
 }

Jackson无法直接将此JSON对象的id和name属性映射到Bag类,因为Bag类不包含任何公共字段或setter方法。

可以通过添加@JsonAnySetter注解来告诉Jackson为所有无法识别的字段调用set()方法,如下所示:

 public class Bag {
 
     private Map<String, Object> properties = new HashMap<>();
 
     @JsonAnySetter
     public void set(String fieldName, Object value){
         this.properties.put(fieldName, value);
     }
 
     public Object get(String fieldName){
         return this.properties.get(fieldName);
     }
 }

现在,Jackson将使用JSON对象中所有无法识别的字段的名称和值调用set()方法。

请记住,这仅对无法识别的字段有效。 例如,如果您向Bag Java类添加了公共名称属性或setName(String)方法,则JSON对象中的名称字段将改为映射到该属性/设置器。

3、@JsonCreator

Jackson注解@JsonCreator用于告诉Jackson该Java对象具有一个构造函数(“创建者”),该构造函数可以将JSON对象的字段与Java对象的字段进行匹配。

@JsonCreator注解在无法使用@JsonSetter注解的情况下很有用。 例如,不可变对象没有任何设置方法,因此它们需要将其初始值注入到构造函数中。

以这个PersonImmutable类为例:

 public class PersonImmutable {
 
     private long   id   = 0;
     private String name = null;
 
     public PersonImmutable(long id, String name) {
         this.id = id;
         this.name = name;
     }
 
     public long getId() {
         return id;
     }
 
     public String getName() {
         return name;
     }
 
 }

要告诉Jackson应该调用PersonImmutable的构造函数,我们必须在构造函数中添加@JsonCreator注解。 但是,仅凭这一点还不够。 我们还必须注解构造函数的参数,以告诉Jackson将JSON对象中的哪些字段传递给哪些构造函数参数。

添加了@JsonCreator和@JsonProperty注解的PersonImmutable类的示例如下:

 public class PersonImmutable {
 
     private long   id   = 0;
     private String name = null;
 
     @JsonCreator
     public PersonImmutable(
             @JsonProperty("id")  long id,
             @JsonProperty("name") String name  ) {
 
         this.id = id;
         this.name = name;
     }
 
     public long getId() {
         return id;
     }
 
     public String getName() {
         return name;
     }
 
 }

请注意,构造函数上方的注解以及构造函数参数之前的注解。 现在,Jackson能够从此JSON对象创建PersonImmutable:

 {
   "id"   : 1234,
   "name" : "John"
 }
4、@JacksonInject

Jackson注解@JacksonInject用于将值注入到解析的对象中,而不是从JSON中读取这些值。 例如,假设正在从各种不同的源下载Person JSON对象,并且想知道给定Person对象来自哪个源。 源本身可能不包含该信息,但是可以让Jackson将其注入到根据JSON对象创建的Java对象中。

要将Java类中的字段标记为需要由Jackson注入其值的字段,请在该字段上方添加@JacksonInject注解。

这是一个示例PersonInject类,在属性上方添加了@JacksonInject注解:

 public class PersonInject {
 
     public long   id   = 0;
     public String name = null;
 
     @JacksonInject
     public String source = null;
 
 }

为了让Jackson将值注入属性,需要在创建Jackson ObjectMapper时做一些额外的工作。

这是让Jackson将值注入Java对象的过程:

 InjectableValues inject = new InjectableValues.Std().addValue(String.class, "jenkov.com");
 PersonInject personInject = new ObjectMapper().reader(inject)
                         .forType(PersonInject.class)
                         .readValue(new File("data/person.json"));

请注意,如何在InjectableValues addValue()方法中设置要注入到source属性中的值。 还要注意,该值仅绑定到字符串类型-而不绑定到任何特定的字段名称。 @JacksonInject注解指定将值注入到哪个字段。

如果要从多个源下载人员JSON对象,并为每个源注入不同的源值,则必须为每个源重复以上代码。

5、@JsonDeserialize

Jackson注解@JsonDeserialize用于为Java对象中给定的属性指定自定义反序列化器类。

例如,假设想优化布尔值false和true的在线格式,使其分别为0和1。

首先,需要将@JsonDeserialize注解添加到要为其使用自定义反序列化器的字段。 这是将@JsonDeserialize注解添加到字段的示例:

 public class PersonDeserialize {
 
     public long    id      = 0;
     public String  name    = null;
 
     @JsonDeserialize(using = OptimizedBooleanDeserializer.class)
     public boolean enabled = false;
 }

其次,这是@JsonDeserialize注解中引用的OptimizedBooleanDeserializer类的实例:

 public class OptimizedBooleanDeserializer
     extends JsonDeserializer<Boolean> {
 
     @Override
     public Boolean deserialize(JsonParser jsonParser,
             DeserializationContext deserializationContext) throws
         IOException, JsonProcessingException {
 
         String text = jsonParser.getText();
         if("0".equals(text)) return false;
         return true;
     }
 }

请注意,OptimizedBooleanDeserializer类使用通用类型Boolean扩展了JsonDeserializer。 这样做会使deserialize()方法返回一个布尔对象。 如果要反序列化其他类型(例如java.util.Date),则必须在泛型括号内指定该类型。

可以通过调用jsonParser参数的getText()方法来获取要反序列化的字段的值。 然后,可以将该文本反序列化为任何值,然后输入反序列化程序所针对的类型(在此示例中为布尔值)。

最后,需要查看使用自定义反序列化器和@JsonDeserializer注解反序列化对象的格式:

 PersonDeserialize person = objectMapper
         .reader(PersonDeserialize.class)
         .readValue(new File("data/person-optimized-boolean.json"));

注意,我们首先需要如何使用ObjectMapper的reader()方法为PersonDeserialize类创建一个阅读器,然后在该方法返回的对象上调用readValue()。

3.3Write注解

Jackson还包含一组注解,这些注解可以影响Jackson将Java对象序列化(写入)到JSON的方式。 以下各节将介绍这些写(序列化)注解中的每一个。

1、@JsonInclude

Jackson注解@JsonInclude告诉Jackson仅在某些情况下包括属性。 例如,仅当属性为非null,非空或具有非默认值时,才应包括该属性。 这是显示如何使用@JsonInclude注解的示例:

 import com.fasterxml.jackson.annotation.JsonInclude;
 
 @JsonInclude(JsonInclude.Include.NON_EMPTY)
 public class PersonInclude {
 
     public long  personId = 0;
     public String name     = null;
 
 }

如果为该示例设置的值是非空的,则此示例将仅包括name属性,这意味着不为null且不是空字符串。

@JsonInclude注解的一个更通俗的名称应该是@JsonIncludeOnlyWhen,但是写起来会更长。

2、@JsonGetter

@JsonGetter Jackson注解用于告诉Jackson,应该通过调用getter方法而不是通过直接字段访问来获取某个字段值。 如果您的Java类使用jQuery样式的getter和setter名称,则@JsonGetter注解很有用。

例如,您可能拥有方法personId()和personId(long id),而不是getPersonId()和setPersonId()。

这是一个名为PersonGetter的示例类,它显示了@JsonGetter注解的用法:

 public class PersonGetter {
 
     private long  personId = 0;
 
     @JsonGetter("id")
     public long personId() { return this.personId; }
 
     @JsonSetter("id")
     public void personId(long personId) { this.personId = personId; }
 
 }

如您所见,personId()方法带有@JsonGetter注解。 @JsonGetter注解上设置的值是JSON对象中应使用的名称。 因此,用于JSON对象中personId的名称是id。 生成的JSON对象如下所示:

 {"id":0}

还要注意,personId(long personId)方法使用@JsonSetter注解进行注解,以使Jackson识别为与JSON对象中的id属性匹配的设置方法。 从JSON读取Java对象时使用@JsonSetter注解-将Java对象写入JSON时不使用。 为了完整起见,仅包含@JsonSetter注解。

3、@JsonAnyGetter

@JsonAnyGetter Jackson注解使您可以将Map用作要序列化为JSON的属性的容器。 这是在Java类中使用@JsonAnyGetter注解的示例:

 public class PersonAnyGetter {
 
     private Map<String, Object> properties = new HashMap<>();
 
     @JsonAnyGetter
     public Map<String, Object> properties() {
         return properties;
     }
 }

当看到@JsonAnyGetter注解时,Jackson将从@JsonAnyGetter注解的方法中获取返回的Map,并将该Map中的每个键值对都视为一个属性。 换句话说,Map中的所有键值对都将作为PersonAnyGetter对象的一部分序列化为JSON。

4、@JsonPropertyOrder

@JsonPropertyOrder Jackson注解可用于指定将Java对象的字段序列化为JSON的顺序。 这是显示如何使用@JsonPropertyOrder注解的示例:

 @JsonPropertyOrder({"name", "personId"})
 public class PersonPropertyOrder {
 
     public long  personId  = 0;
     public String name     = null;
 
 }

通常,Jackson会按照在类中找到的顺序序列化PersonPropertyOrder中的属性。 但是,@JsonPropertyOrder注解指定了不同的顺序,在序列化的JSON输出中,name属性将首先出现,personId属性将随后出现。

5、@JsonRawValue

@JsonRawValue Jackson注解告诉Jackson该属性值应直接写入JSON输出。 如果该属性是字符串,Jackson通常会将值括在引号中,但是如果使用@JsonRawValue属性进行注解,Jackson将不会这样做。

为了更清楚@JsonRawValue的作用,看看没有使用@JsonRawValue的此类:

 public class PersonRawValue {
 
     public long   personId = 0;
 
     public String address  = "$#";
 }

Jackson会将其序列化为以下JSON字符串:

 {"personId":0,"address":"$#"}

现在,我们将@JsonRawValue添加到address属性,如下所示:

 public class PersonRawValue {
 
     public long   personId = 0;
 
     @JsonRawValue
     public String address  = "$#";
 }

现在,当对地址属性进行序列化时,杰克逊将省略引号。 因此,序列化的JSON如下所示:

 {"personId":0,"address":$#}

当然它是无效的JSON,那么为什么要这么做呢?

如果address属性包含一个JSON字符串,那么该JSON字符串将被序列化为最终的JSON对象,作为JSON对象结构的一部分,而不仅是序列化为JSON对象的address字段中的字符串。

要查看其工作原理,让我们像下面这样更改address属性的值:

 public class PersonRawValue {
 
     public long   personId = 0;
 
     @JsonRawValue
     public String address  =
             "{ "street" : "Wall Street", "no":1}";
 
 }

Jackson会将其序列化为以下JSON:

 {"personId":0,"address":{ "street" : "Wall Street", "no":1}}

请注意,JSON字符串现在如何成为序列化JSON结构的一部分。

没有@JsonRawValue注解,Jackson会将对象序列化为以下JSON:

 {"personId":0,"address":"{ "street" : "Wall Street", "no":1}"}

请注意,address属性的值现在如何用引号引起来,并且值内的所有引号均被转义。

6、@JsonValue

Jackson注解@JsonValue告诉Jackson,Jackson不应该尝试序列化对象本身,而应在对象上调用将对象序列化为JSON字符串的方法。 请注意,Jackson将在自定义序列化返回的String内转义任何引号,因此不能返回例如 完整的JSON对象。 为此,应该改用@JsonRawValue(请参阅上一节)。

@JsonValue注解已添加到Jackson调用的方法中,以将对象序列化为JSON字符串。 这是显示如何使用@JsonValue注解的示例:

 public class PersonValue {
 
     public long   personId = 0;
     public String name = null;
 
     @JsonValue
     public String toJson(){
         return this.personId + "," + this.name;
     }
 
 }

要求Jackson序列化PersonValue对象所得到的输出是:

 "0,null"

引号由Jackson添加。 请记住,对象返回的值字符串中的所有引号均会转义。

7、@JsonSerialize

@JsonSerialize Jackson注解用于为Java对象中的字段指定自定义序列化程序。 这是一个使用@JsonSerialize注解的Java类示例:

 public class PersonSerializer {
 
     public long   personId = 0;
     public String name     = "John";
 
     @JsonSerialize(using = OptimizedBooleanSerializer.class)
     public boolean enabled = false;
 }

注意启用字段上方的@JsonSerialize注解。

OptimizedBooleanSerializer将序列的真值序列化为1,将假值序列化为0。这是代码:

  public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {
  
      @Override
      public void serialize(Boolean aBoolean, JsonGenerator jsonGenerator, 
          SerializerProvider serializerProvider) 
      throws IOException, JsonProcessingException {
  
          if(aBoolean){
              jsonGenerator.writeNumber(1);
          } else {
              jsonGenerator.writeNumber(0);
          }
      }
  }

4.使用过滤器忽略字段

首先,我们需要在目标Java对象上定义过滤器:

 @JsonFilter("excludesFilter")
 public class BaseEntity implements Serializable
 {
     private static final long serialVersionUID = 1L;
 ​
     /** 搜索值 */
     @JsonIgnore
     private String searchValue;
 ​
     /** 创建者 */
     private String createBy;
 ​
     /** 创建时间 */
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
     //..
 }

我们定义一个简单的过滤器,该过滤器将忽略userName字段

 SimpleBeanPropertyFilter excludesFilter = SimpleBeanPropertyFilter.serializeAllExcept("userName");  
 FilterProvider filters = new SimpleFilterProvider().addFilter("excludesFilter", excludesFilter); 

测试一下

 ObjectMapper objectMapper = new ObjectMapper();
 SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter.serializeAllExcept("userName");
 FilterProvider filters = new SimpleFilterProvider().addFilter("excludesFilter", theFilter);
 ​
 SysUser sysUser = new SysUser();
 sysUser.setUserName("ldk");
 ​
 String s = objectMapper.setFilterProvider(filters).writeValueAsString(sysUser);
 System.out.println(s);

把过滤器加入全局OjectMapper中

 @Configuration
 public class FilterConfiguration {
     public FilterConfiguration (ObjectMapper objectMapper) {
         SimpleFilterProvider simpleFilterProvider = new SimpleFilterProvider();
         simpleFilterProvider.addFilter("excludesFilter", SimpleBeanPropertyFilter.serializeAll());
         objectMapper.setFilterProvider(simpleFilterProvider);
     }
 }

5.转json时加入类名

 ObjectMapper mapper = new ObjectMapper();
 mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);

activateDefaultTyping()方法启用默认的类型信息。

  • LaissezFaireSubTypeValidator.instance - 这是一个子类型验证器,用于限制类型信息的范围。LaissezFaireSubTypeValidator是Jackson库提供的默认验证器之一。
  • ObjectMapper.DefaultTyping.NON_FINAL - 这是一个枚举值,指定了默认的类型信息的处理方式。NON_FINAL表示只在非最终类(即非final类)中包含类型信息。
  • JsonTypeInfo.As.WRAPPER_ARRAY - 这是一个枚举值,指定了类型信息的包装方式。WRAPPER_ARRAY表示将类型信息包装在JSON数组中

示例:

 ["com.ruoyi.common.core.domain.entity.SysUser", {
     "deptId": null,
     "userName": "admin"
     }
 ]

JsonTypeInfo.As.WRAPPER_OBJECT示例:

 {
     "com.ruoyi.common.core.domain.entity.SysUser": {
         "createBy": null,
         "userName": "admin"
     }
 }

JsonTypeInfo.As.PROPERTY示例:

 {
     "@class": "com.ruoyi.common.core.domain.entity.SysUser",
     "deptId": null,
     "userName": "admin"
 }

四、配置大全:

 spring:
   jackson:
     # 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
     property-naming-strategy: SNAKE_CASE
     # 全局设置@JsonFormat的格式pattern
     date-format: yyyy-MM-dd HH:mm:ss
     # 当地时区
     locale: zh_CN
     # 设置全局时区
     time-zone: GMT+8
     # 常用,全局设置pojo或被@JsonInclude注解的属性的序列化方式
     default-property-inclusion: NON_NULL #不为空的属性才会序列化,具体属性可看JsonInclude.Include
     # 常规默认,枚举类SerializationFeature中的枚举属性为key,值为boolean设置jackson序列化特性,具体key请看SerializationFeature源码
     visibility:
       #属性序列化的可见范围
       getter: non_private
       #属性反序列化的可见范围
       setter: protected_and_public
       #静态工厂方法的反序列化
       CREATOR: public_only
       #字段
       FIELD: public_only
       #布尔的序列化
       IS_GETTER: public_only
       #所有类型(即getter setter FIELD)不受影响,无意义
       NONE: public_only
       #所有类型(即getter setter FIELD)都受其影响(慎用)
       ALL: public_only
     serialization:
       #反序列化是否有根节点
       WRAP_ROOT_VALUE: false
       #是否使用缩进,格式化输出
       INDENT_OUTPUT: false
       FAIL_ON_EMPTY_BEANS: true # 对象不含任何字段时是否报错,默认true
       FAIL_ON_SELF_REFERENCES: true #循环引用报错
       WRAP_EXCEPTIONS: true #是否包装异常
       FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS: true #JsonUnwrapped标记的类有类型信息是否报错
       WRITE_SELF_REFERENCES_AS_NULL: false #循环引用返回null
       CLOSE_CLOSEABLE: true #若对象实现了CLOSEABLE接口,在序列化后是否调用Close方法
       FLUSH_AFTER_WRITE_VALUE: false #流对象序列化之后是否强制刷新
       WRITE_DATES_AS_TIMESTAMPS: true # 返回的java.util.date转换成时间戳
       WRITE_DATES_WITH_ZONE_ID: true #2011-12-03T10:15:30+01:00[Europe/Paris]带时区id
       WRITE_DURATIONS_AS_TIMESTAMPS: true #将DURATIONS转换成时间戳
       WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS: false #是否字符数组输出json数组 (false则输出字符串)
       WRITE_ENUMS_USING_TO_STRING: false # 将枚举输出toString
       WRITE_ENUMS_USING_INDEX: false #枚举下标
       WRITE_ENUM_KEYS_USING_INDEX: false #枚举key类似
       WRITE_NULL_MAP_VALUES: false #是否输出map中的空entry(此特性已过期,请使用JsonInclude注解)
       WRITE_EMPTY_JSON_ARRAYS: true # 对象属性值是空集合是否输出空json数组
       WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED: false #是否将单个元素的集合展开,(即:去除数组符号"[]")
       WRITE_BIGDECIMAL_AS_PLAIN: false #是否调用BigDecimal#toPlainString()输出
       WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS: #将timestamp输出为纳秒
       ORDER_MAP_ENTRIES_BY_KEYS: false #map序列化后,是否用key对其排序
       EAGER_SERIALIZER_FETCH: true #是否马上获取序列化器
       USE_EQUALITY_FOR_OBJECT_ID: false #是否使用objectId比较是否相等(在ORM框架Hibernate中有应用)
  
     # 枚举类DeserializationFeature中的枚举属性为key,值为boolean设置jackson反序列化特性,具体key请看DeserializationFeature源码
     deserialization:
       USE_BIG_DECIMAL_FOR_FLOATS: false #将浮点数反序列化为BIG_DECIMAL
       USE_BIG_INTEGER_FOR_INTS: false #将整数反序列化为BIG_INTEGER
       USE_LONG_FOR_INTS: false #将整型反序列化为长整
       USE_JAVA_ARRAY_FOR_JSON_ARRAY: false #无明确类型时,是否将json数组反序列化为java数组(若是true,就对应Object[] ,反之就是List<?>)
       FAIL_ON_UNKNOWN_PROPERTIES: false # 常用,json中含pojo不存在属性时是否失败报错,默认true
       FAIL_ON_NULL_FOR_PRIMITIVES: false #将null反序列化为基本数据类型是否报错
       FAIL_ON_NUMBERS_FOR_ENUMS: false #用整数反序列化为枚举是否报错
       FAIL_ON_INVALID_SUBTYPE: false #找不至合适的子类否报错 (如注解JsonTypeInfo指定的子类型)
       FAIL_ON_READING_DUP_TREE_KEY: false #出现重复的json字段是否报错
       FAIL_ON_IGNORED_PROPERTIES: false #如果json中出现了java实体字段中已显式标记应当忽略的字段,是否报错
       FAIL_ON_UNRESOLVED_OBJECT_IDS: true #如果反序列化发生了不可解析的ObjectId是否报错
       FAIL_ON_MISSING_CREATOR_PROPERTIES: false #如果缺少静态工厂方法的参数是否报错(false,则使用null代替需要的参数)
       FAIL_ON_NULL_CREATOR_PROPERTIES: false #将空值绑定到构造方法或静态工厂方法的参数是否报错
       FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY: false #注解JsonTypeInfo.As#EXTERNAL_PROPERTY标记的属性缺失,是否报错
       FAIL_ON_TRAILING_TOKENS: false #出现尾随令牌是否报错(如果是true,则调用JsonParser#nextToken,检查json的完整性)
       WRAP_EXCEPTIONS: true #是否包装反序列化出现的异常
       ACCEPT_SINGLE_VALUE_AS_ARRAY: true #反序列化时是否将一个对象封装成单元素数组
       UNWRAP_SINGLE_VALUE_ARRAYS: false #反序列化时是否将单元素数组展开为一个对象
       UNWRAP_ROOT_VALUE: false #是否将取消根节点的包装
       ACCEPT_EMPTY_STRING_AS_NULL_OBJECT: false #是否将空字符("")串当作null对象
       ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT: false #是否接受将空数组("[]")作为null
       ACCEPT_FLOAT_AS_INT: true #是否接受将浮点数作为整数
       READ_ENUMS_USING_TO_STRING: false #按照枚举toString()方法读取,(false则按枚举的name()方法读取)
       READ_UNKNOWN_ENUM_VALUES_AS_NULL: false #读取到未知的枚举当作null
       READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE: false #读取到未知的枚举,将其当作被JsonEnumDefaultValue注解标记的枚举
       READ_DATE_TIMESTAMPS_AS_NANOSECONDS: true #将时间戳视为纳秒(false,则视为毫秒)
       ADJUST_DATES_TO_CONTEXT_TIME_ZONE: true #反序列化是否会适应DeserializationContext#getTimeZone()提供的时区 (此特性仅对java8的时间/日期有效)
       EAGER_DESERIALIZER_FETCH: true  #是否马上获取反序列化器
     # 枚举类MapperFeature中的枚举属性为key,值为boolean设置jackson ObjectMapper特性
     # ObjectMapper在jackson中负责json的读写、json与pojo的互转、json tree的互转,具体特性请看MapperFeature,常规默认即可
     mapper:
       USE_ANNOTATIONS: true #是否使用注解自省(检查JsonProperties这些)
       # 使用getter取代setter探测属性,这是针对集合类型,可以直接修改集合的属性
       USE_GETTERS_AS_SETTERS: true #默认false
       PROPAGATE_TRANSIENT_MARKER: false #如何处理transient字段,如果true(不能访问此属性) ,若是false则不能通过字段访问(还是可以使用getter和setter访问)
       AUTO_DETECT_CREATORS: true #是否自动检测构造方法或单参且名为valueOf的静态工厂方法
       AUTO_DETECT_FIELDS: true #是否自动检测字段 (若true,则将所有public实例字段视为为属性)
       AUTO_DETECT_GETTERS: true #确定是否根据标准 Bean 命名约定自动检测常规“getter”方法的(不包括is getter)
       AUTO_DETECT_IS_GETTERS: true #确定是否根据标准 Bean 命名约定自动检测“is getter”方法
       AUTO_DETECT_SETTERS: false # 确定是否根据标准 Bean 命名约定自动检测“setter”方法
       REQUIRE_SETTERS_FOR_GETTERS: false #getter方法必需要有对应的setter或字段或构造方法参数,才能视为一个属性
       ALLOW_FINAL_FIELDS_AS_MUTATORS: true #是否可以修改final成员字段
       INFER_PROPERTY_MUTATORS: true #是否能推断属性,(即使用字段和setter是不可见的,但getter可见即可推断属性)
       INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES: true #是否自动推断ConstructorProperties注解
       CAN_OVERRIDE_ACCESS_MODIFIERS: true #调用AccessibleObject#setAccessible设为true .将原来不可见的属性,变为可见
       OVERRIDE_PUBLIC_ACCESS_MODIFIERS: true #对所有的属性调用AccessibleObject#setAccessible设为true .(即使用是公共的)
       USE_STATIC_TYPING: false #序列化使用声明的静态类型还是动态类型  JsonSerialize#typing注解可覆盖它
       USE_BASE_TYPE_AS_DEFAULT_IMPL: false # 反序列化是否使用基本类作为默实现 @JsonTypeInfo.defaultImpl
       DEFAULT_VIEW_INCLUSION: true #没有JsonView注解标记的属性是否会被包含在json序列化视图中
       SORT_PROPERTIES_ALPHABETICALLY: false #按字母表顺序序列化字段(若false,按字段声明的顺序)
       ACCEPT_CASE_INSENSITIVE_PROPERTIES: false #反序列化属性时不区分大小写 (true时,会影响性能)
       ACCEPT_CASE_INSENSITIVE_ENUMS: false #枚举反序列化不区别大小写
       ACCEPT_CASE_INSENSITIVE_VALUES: false #允许解析一些枚举的基于文本的值类型但忽略反序列化值的大小写 如日期/时间类型反序列化器
       USE_WRAPPER_NAME_AS_PROPERTY_NAME: false # 使用包装器名称覆盖属性名称 AnnotationIntrospector#findWrapperName指定的
       USE_STD_BEAN_NAMING: false # 是否以强制与 Bean 名称自省严格兼容的功能,若开启后(getURL())变成URL (jackson默认false, url)
       ALLOW_EXPLICIT_PROPERTY_RENAMING: false #是否允许JsonProperty注解覆盖PropertyNamingStrategy
       ALLOW_COERCION_OF_SCALARS: true # 是否允许强制使用文本标题 ,即将字符串的"true"当作布尔的true ,字符串的"1.0"当作"double"
       IGNORE_DUPLICATE_MODULE_REGISTRATIONS: true #如果模块相同(Module#getTypeId()返回值相同),只有第一次能会真正调用注册方法
       IGNORE_MERGE_FOR_UNMERGEABLE: true #在合并不能合并的属性时是否忽略错误
       BLOCK_UNSAFE_POLYMORPHIC_BASE_TYPES: false #阻止不安全的基类(如Object Closeable Cloneable AutoCloseable Serializable)
     parser:
       AUTO_CLOSE_SOURCE: true #是否自动关闭不属于解析器的底层输入流
       ALLOW_COMMENTS: false #是否允许json注解(Json规范是不能加注释的,但这里可以配置)
       ALLOW_YAML_COMMENTS: false #是否允许出现yaml注释
       ALLOW_UNQUOTED_FIELD_NAMES: false #是否允许出现字段名不带引号
       ALLOW_SINGLE_QUOTES: false # 是否允许出现单引号,默认false
       ALLOW_UNQUOTED_CONTROL_CHARS: false #是否允许出现未加转义的控制字符
       ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER: false #是否允许对所有字符都可加反斜杠转义
       ALLOW_NUMERIC_LEADING_ZEROS: false #是否允许前导的零 000001
       ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS: false #是否允许前导的小点数 如 ".04314"会被解析成"0.04314"
       ALLOW_NON_NUMERIC_NUMBERS: false #是否允许NaN型的浮点数 ("INF"当作正无穷  "-INF"当作负无穷 "NaN"非数字,类型于除数为0)
       ALLOW_MISSING_VALUES: false # 是否允许json数组中出现缺失值 (如["value1",,"value3",]将被反序列化为["value1", null, "value3", null])
       ALLOW_TRAILING_COMMA: false # 是否允许json尾部有逗号 (如{"a": true,})
       STRICT_DUPLICATE_DETECTION: false #是否启用严格的字段名重复检查(开启后会增加20-30%左右的性能开销)
       IGNORE_UNDEFINED: false #属性定义未找到是否报错(这不是针对json,是针对Avro, protobuf等需要Schema的格式)
       INCLUDE_SOURCE_IN_LOCATION: false #是否包含其源信息(如总字节数,总字符数 行号 列号 )
     generator:
       AUTO_CLOSE_TARGET: true #是否自动关闭不属于生成器的底层输出流
       AUTO_CLOSE_JSON_CONTENT: true #是否自动补全json(当有不匹配的JsonToken#START_ARRAY JsonToken#START_OBJECT时)
       FLUSH_PASSED_TO_STREAM: true #是否刷新generator
       QUOTE_FIELD_NAMES: true #是否为字段名添加引号
       QUOTE_NON_NUMERIC_NUMBERS: true #对于NaN浮点数是否加引号
       ESCAPE_NON_ASCII: false #非ASCII码是否需要转义
       WRITE_NUMBERS_AS_STRINGS: false #将数字当作字符串输出 (防止Javascript长度限制被截断)
       WRITE_BIGDECIMAL_AS_PLAIN: false #按BigDecimal的toPlainString()输出
       STRICT_DUPLICATE_DETECTION: false #是否启用严格的字段名重复检查
       IGNORE_UNKNOWN: false #属性定义未找到是否报错(这不是针对json,是针对Avro, protobuf等需要Schema的格式)