Jackson使用进阶

实现

注解

属性命名

@JsonProperty

定义属性序列化时的名称。

@JacksonAnnotation
public @interface JsonProperty
{
    public final static String USE_DEFAULT_NAME = "";
    public final static int INDEX_UNKNOWN = -1;
	//指定属性的名称。
    String value() default USE_DEFAULT_NAME;
    boolean required() default false;
    //如果数据格式(JSON 除外)是基于索引的,则要使用的物理索引
    int index() default INDEX_UNKNOWN;
    //定义为元数据的文本默认值。注意:核心数据绑定不会使用此值;它目前仅向扩展模块公开。
    String defaultValue() default "";
    //用来控制是否 能被【序列化】或者【反序列化】,默认是不受控制的。
    Access access() default Access.AUTO;
    
    public enum Access
    {
        AUTO,
        //仅做序列化操作
        READ_ONLY,
        //仅做反序列化操作
        WRITE_ONLY,
        //都可以
        READ_WRITE
        ;
    }
}

属性包含

@JsonAutoDetect

注解在类上,用于覆盖属性的定义。

public @interface JsonAutoDetect
{
    /** 可视化
     */
    public enum Visibility {
        /** 所有的访问限制符都可以。从private 到 public */
        ANY,
        /** 非 Private 是 自动侦测的。 */
        NON_PRIVATE,
        /** protected 和 public 是 自动侦测的  */
        PROTECTED_AND_PUBLIC,
        /** 仅 public 是 自动侦测的  */
        PUBLIC_ONLY,
        /** 所有都不自动侦测,用于关闭自动侦测 */
        NONE,
        
        /** 由 context 决定 */
        DEFAULT;
 
    }
    
    /**
     * getter 最小 可视化需求
     */
    Visibility getterVisibility() default Visibility.DEFAULT;
    Visibility isGetterVisibility() default Visibility.DEFAULT;
    Visibility setterVisibility() default Visibility.DEFAULT;
    Visibility creatorVisibility() default Visibility.DEFAULT;
    Visibility fieldVisibility() default Visibility.DEFAULT;

}

@JsonIgnore

注解用于属性或者方法上,用来完全忽略被注释的字段和方法对应的属性。

放在getter上也会禁用setter,除非在setter上放置 @JsonProperty

@JsonIgnoreProperties

注解在类上,用于忽略指定的属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
    ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonIgnoreProperties
{
    /**
     * Names of properties to ignore.
     */
    public String[] value() default { };
 	//反序列化时,忽略 未知的json 属性。
    public boolean ignoreUnknown() default false;
 
    public boolean allowGetters() default false;
    public boolean allowSetters() default false;
}

@JsonIgnoreType

注解在类上,用于忽略指定 类型 的属性。

@JsonInclude

用于排除值为empty/null/default的属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD,
    ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonInclude
{
    //包含策略
    public Include value() default Include.ALWAYS;

    /** Map,AtomicReference 等entity 的 规则      */
    public Include content() default Include.ALWAYS;

    /**  value 属性设置为CUSTOM时,配合 过滤*/
    public Class<?> valueFilter() default Void.class;

     /**  content 属性设置为CUSTOM时,配合 过滤*/
    public Class<?> contentFilter() default Void.class;
    
 
    public enum Include
    {
        /** 属性一直被包含,无关具体属性值 */
        ALWAYS,

        /** 非空值才会被包含 **/
        NON_NULL,

        /**Optional或AtomicReference引用的实例为null时,也可使该字段不做序列化,同时可以排除值为null的字段*/
        NON_ABSENT,

        /** 排除字段值为null、空字符串、空集合、空数组、Optional类型引用为空,AtomicReference类型引用为空 */
        NON_EMPTY,

        /** 排除 是指定类型的默认值的 属性 */
        NON_DEFAULT,

        /**配合valueFilter属性一起使用,在序列化的时候会执行CustomFilter中的的equals方法,该方法的入参就是字段的值,如果equals方法返回true,字段就不会被序列化,如果equals方法返回false时字段才会被序列化*/
        CUSTOM,
        
        /** 使用默认设置
         */
        USE_DEFAULTS
        
        ;
    }

@JsonFilter

属性文档与元数据

@JsonPropertyDescription

用于生成字段的描述信息。

序列化与反序列化细节

@JsonFormat

用于格式化日期/时间格式的数据。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
    ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonFormat
{
 
    public final static String DEFAULT_LOCALE = "##default";
    public final static String DEFAULT_TIMEZONE = "##default";
 	//指定格式化字符串,例如:YYYY-MM-DD
    public String pattern() default "";
 	// 序列化后的类型
    public Shape shape() default Shape.ANY;
   //默认locale
    public String locale() default DEFAULT_LOCALE;
   //默认时区
    public String timezone() default DEFAULT_TIMEZONE;
   //
    public OptBoolean lenient() default OptBoolean.DEFAULT;
 	//
    public JsonFormat.Feature[] with() default { };
 	//
    public JsonFormat.Feature[] without() default { };
    //JSON 的数据类型
    public enum Shape
    {
        ANY,
        NATURAL,
        SCALAR,
        ARRAY,
        OBJECT,
        NUMBER,
        NUMBER_FLOAT,
        NUMBER_INT,
        STRING,
        BOOLEAN,
        BINARY
        ;
}

@JsonUnwrapped

将对象扁平,即将属性实体的属性作为本对象的属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonUnwrapped
{
    boolean enabled() default true;

    /** 输出属性名的前缀 */
    String prefix() default "";

     /** 输出属性名的后缀 */
    String suffix() default "";
}
class Employee {
   public int empId = 110;
   public String empName = "Raja Ramesh";
   @JsonUnwrapped
   public Address address = new Address();
   //地址类别 
   public static class Address {
      public String doorNumber = "1118";
      public String street = "madhapur";
      public String pinCode = "500081";
      public String city = "Hyderabad";
   }
}

结果:

{
   "empId" : 110,
   "empName" : "Raja Ramesh",
   "doorNumber" : "1118",
   "street" : "madhapur",
   "pinCode" : "500081",
   "city" : "Hyderabad"
}

@JsonView

可以用于过滤属性。适用于在不同场景下,同一个字段是否输出。比如密码,在某些情况下返回,某些情况下不返回。

public class JsonViewTest {

   //定义了2个场景
    public interface SimpleView{};
    public interface DetailView extends SimpleView{} ;


    private static class User{
        static ObjectMapper objectMapper = new ObjectMapper();
        
        private String age;
        @JsonView(SimpleView.class)
        private String userName;
        @JsonView(DetailView.class)
        private String password;
        private String sex;


        public static String getSimpleView()throws Exception{
            User user = getUser();
            return objectMapper.writerWithView(SimpleView.class).writeValueAsString(user);
        }

        public static String getDetailView()throws Exception{
            User user = getUser();
            return objectMapper.writerWithView(DetailView.class).writeValueAsString(user);
        }

        private static User getUser() {
            User user = new User();
            user.setAge("11111");
            user.setPassword("pwd");
            user.setSex("man");
            user.setUserName("name");
            return user;
        }

    }
}

User.getSimpleView() 结果:

{"age":"11111","userName":"name","sex":"man"}

(User.getDetailView() 结果:

{"age":"11111","userName":"name","password":"pwd","sex":"man"}

没有加 @JsonView 的属性,则忽略场景。

Spring MVC 的使用
@RestController
public class SimpleRestController {
    @Autowired
    SimpleService simpleService;
    @RequestMapping(value = "/user/simple", method = RequestMethod.GET)
    @JsonView(SimpleView.class)
    public User getUserWithSimpleData() {
        return User.getUser();
    }
    @RequestMapping(value = "/user/detail", method = RequestMethod.GET)
    @JsonView(DetailView.class)
    public User getUserWithDetailData() {
        return User.getUser();
    }
}

在方法上加@JsonView,则会在Spring MVC调用 objectMapper时,自动应用。

反序列化细节

@JsonAlias

指定属性的一个或多个别名,只用于反序列化。即属性可以从多个JSON KEY中获取到值。可指定多个别名。

@JsonMerge

通过JSON字符串对已存在的对象实例进行更新。仅当属性值为null时,才会更新。

@JacksonInject

指定某个字段从注入赋值,而不是从Json。如果一个属性用 @JacksonInject 注解,并且我们使用 ObjectMapper 注入了值,那么默认情况下如果没有对应的 JSON 字段,注入的值将是属性的值,如果有对应的 JSON 字段,则属性值将被相应的覆盖为JSON 字段值。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JacksonInject
{
    /** 注入值的逻辑id,如果没有指定,则根据属性类型注入 */
    public String value() default "";

    /** 决定 匹配的输入值是否覆盖注解的属性。如果该值为 false,则输入值将被忽略。如果值为 true,则输入值将覆盖注入值。 */
    public OptBoolean useInput() default OptBoolean.DEFAULT;
}

使用 ObjectMapper 类的 setInjectableValues 方法注入值。

指定value属性示例:

@JacksonInject("wnameInput")
private String name;
	
@JacksonInject("bookInput")
private Book book;
 
injectableValues.addValue("wnameInput","Mahesh");
injectableValues.addValue("bookInput", new Book("Hibernate Tutorial", "Hibernate"));
mapper.setInjectableValues(injectableValues);

不指定value属性示例:

@JacksonInject
private String name;
	
@JacksonInject
private Book book;

injectableValues.addValue(String.class,"Mahesh");
injectableValues.addValue(Book.class, new Book("Hibernate Tutorial", "Hibernate"));
		 
mapper.setInjectableValues(injectableValues);

使用:


// InjectableValues
InjectableValues.Std injectableValues = new InjectableValues.Std();
injectableValues.addValue(String.class,"Default Value");
injectableValues.addValue("bookInput", new Book("Hibernate Tutorial", "Hibernate"));

ObjectMapper mapper = new ObjectMapper();
mapper.setInjectableValues(injectableValues);
//json 转对象
Writer writer = mapper.readValue(jsonData, Writer.class);
System.out.println(writer.getId()+", "+ writer.getName());
Book book = writer.getBook();
System.out.println(book.getName()+", "+ book.getCategory());

@JsonAnySetter

标记在setter方法上或属性上,此方法参数为键值对,反序列化时所有不包含在对象中的未知属性都会调用此setter方法设置。

 
class Book {
    private String name;
    //除了name属性,其他的属性都放置到 properties中。
    @JsonAnySetter
    private Map<String, String> properties = new HashMap<>();
 
    public Map<String, String> getProperties() {
        return properties;
    }
 
    public void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }
    /**
    或者使用此方法
    @JsonAnySetter
    public void setAdditionalProperty(String name, Object value) {
        this.additionalProperties.put(name, value);
    }
    */
}
 

@JsonCreator

为Java对象创建指定一个构造方法,在无法使用@JsonSetter注解的情况下很有用。例如,不可变对象没有任何设置方法,因此它们需要将其初始值注入到构造函数中。即通过构造函数,设置对象属性。

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;
     } 

} 

@JsonSetter

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

class Book {
    private String name;
    //把JSON中的 bookName 属性值 读取 为 这个 方法。则设置了name的值。
    @JsonSetter("bookName")
    public void setName(String name){
    	this.name = name;
    }
}    

@JsonEnumDefaultValue

可以通过 @JsonEnumDefaultValue 注解为未知的枚举类型赋一个默认值来兜底,但要记得在 ObjectMapper 中手动开启该功能。

private enum Sex {
    MAN,
    WOMAN,
    @JsonEnumDefaultValue
    UNKNOWN
}

序列化细节

@JsonAnyGetter

可以将Map用作要序列化为JSON的属性。

@JsonGetter

指定某个方法的返回值,用做JSON属性的值。

@JsonPropertyOrder

指定序列化时属性的顺序。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
    ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPropertyOrder
{
    /**
     * 在此处指定属性的顺序,属性的数组。
     */
    public String[] value() default { };

    /** 按字母顺序*/
    public boolean alphabetic() default false;
}

@JsonRawValue

会将字符串形式的 JSON 也尝试序列化为对象。即如果属性是JSON字符串,则会序列化为JSON对象,而不再是个String属性。

@JsonValue

不要由jackson序列化,而是调用 加此注解的方法的返回值作为JSON 串。比如 @JsonValue toJson() 方法。

@JsonRootName

指定JSON对象的根名称。即把输出的JSON再包装一层,指定给设置的属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@com.fasterxml.jackson.annotation.JacksonAnnotation
public @interface JsonRootName
{
    public String value();
 
    public String namespace() default "";
 
}
 @JsonRootName("user")
 class User{
	private String age;
	private String userName;
	private String sex;
}
//输出:设置了根属性。
{"user":
    {"age":"11111","userName":"name","sex":"man"}
}	

@JsonAppend

在序列化时额外添加指定的属性。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@com.fasterxml.jackson.annotation.JacksonAnnotation
public @interface JsonAppend
{
    /** 属性支持的属性 */
    public Attr[] attrs() default { };

    /**
     * 通用虚拟属性。.
     */
    public Prop[] props() default { };

    /** 虚拟属性附加在常规属性前面还是右面,默认false(后面) */
    public boolean prepend() default false;

    /** 单个属性定义。 */
    public @interface Attr
    {
        /** 属性名称,也用于扩展属性,直到被propName 覆盖。  */
        public String value();

        /** 属性名称,如果未定义,则使用value属性。 */
        public String propName() default "";

        /** xml的属性namespace。 */
        public String propNamespace() default "";

        public JsonInclude.Include include() default JsonInclude.Include.NON_NULL;

        public boolean required() default false;
    }
    
    /**
     * Definition of a single general virtual property.
     */
    public @interface Prop
    {
        /* 要实例化的属性的实际实现类(VirtualBeanPropertyWriter子类)  */
        public Class<? extends VirtualBeanPropertyWriter> value();

        /**可能用于序列化的属性的名称(尽管实现可以选择不使用此信息)。*/
        public String name() default "";

        /** xml namespace */
        public String namespace() default "";

        /** 何时包含属性值。 NON_NULL 指示 仅当属性值不为null时才写。其他值,与其他属性一样,实际的属性实现可以选择也可以不选择使用此包含信息。*/
        public JsonInclude.Include include() default JsonInclude.Include.NON_NULL;

        /**
         * Metadata about property, similar to
         * {@link com.fasterxml.jackson.annotation.JsonProperty#required()}.
         */
        public boolean required() default false;

        /** 属性的名义类型。作为相关虚拟对象的类型信息传递,实现可以(也可以不)使用它来选择要使用的序列化器。  */
        public Class<?> type() default Object.class;
    }
}

多态类型处理

多态类型处理主要是解决派生类的序列化与反序列化问题。比如Animal 的子类 Dog,Cat 等。

@JsonTypeId

标识注解,用在字段、getter、setter、构造函数参数上,用以指示是个多态类型。

@JsonTypeInfo

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE,
    ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeInfo
{    
    public enum Id {
        NONE(null),
        CLASS("@class"),
        MINIMAL_CLASS("@c"),
        NAME("@type"),
        CUSTOM(null)
        ;
        // 默认属性名称。
        private final String _defaultPropertyName;

        private Id(String defProp) {
            _defaultPropertyName = defProp;
        }

        public String getDefaultPropertyName() { return _defaultPropertyName; }
    }
 
    public enum As {
        PROPERTY,
        WRAPPER_OBJECT,
        WRAPPER_ARRAY,
        EXTERNAL_PROPERTY,
        EXISTING_PROPERTY
        ;
    }
    
    
    /** 这个字段是用来指定根据哪种类型的元数据来进行序列化和反序列化  */
    public Id use();    
    
    /** 这个字段是用来指定元信息是如何被包含进去的   */
    public As include() default As.PROPERTY;

    /** 只用当`use`为`JsonTypeInfo.Id.CUSTOM`,或者`include`为`JsonTypeInfo.As.PROPERTY`时才会配置这个值。这个就可以用来表示具体的依据字段。 */
    public String property() default "";
   //如果类型识别码不存在或者无效,可以使用该属性来制定反序列化时使用的默认类型
    public Class<?> defaultImpl() default JsonTypeInfo.class;
   /**定义了类型标识符的值是否会通过JSON流成为反序列化器的一部分,默认为fale,也就是说,jackson会从JSON内容中处理和删除类型标识符再传递给JsonDeserializer。
   */
    public boolean visible() default false;
}   

use解释

用于指定子类用什么来进行区分。

  • NONE:不包括显式的类型元数据,类型完全是使用上下文信息完成的,可能还添加了其他注解。
  • CLASS:类型的全限定名作为类的标识符。
  • MINIMAL_CLASS:若基类和子类在同一包类,使用相对于基类的相对全限名作为识别码。例如基类com.foobar.Base的具体类 com.foo.Impl 的id为.Impl,具体类com.foo.impl.Impl2的id为.impl.Impl2。(注意前导点号)
  • NAME:通过某个属性来区分标识不同类型。在序列化时,属性值为类的Name。
  • CUSTOM:自定义识别码,由@JsonTypeIdResolver解析。
include解释
  • PROPERTY:作为数据的属性的兄弟属性(即平级的)
  • EXISTING_PROPERTY:作为POJO中已经存在的属性。反序列化时与PROPERTY一样的处理逻辑。在序列化时,TypeSerializer不起作用。
  • EXTERNAL_PROPERTY:作为扩展属性。与PROPERTY类似,除了在层级结构的第一层,仅放在属性上而不是类上。
  • WRAPPER_OBJECT:作为一个包装的对象,即对象的现有属性作为一个包装对象的属性。
  • WRAPPER_ARRAY:作为一个包装的数组
property解释

property属性只有当:

  • use为:JsonTypeInfo.Id.CLASSJsonTypeInfo.Id.MINIMAL_CLASSJsonTypeInfo.Id.NAME

  • include为:JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY

时才有效。

@JsonTypeInfo在属性(字段,方法)上使用时,此注解适用于值。 当在集合类型(List,Map,Array)上使用时,它将应用于元素,而不是集合本身。 对于非集合类型,没有区别。

@JsonTypeName

指定用于带注解的类的逻辑类型名称。如果在@JsonSubTypes.Type中定义了 Name 属性,这优先使用它,否则使用@JsonTypeName的值。

@JsonSubTypes

指定带注解类型的子类型。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.FIELD,
    ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSubTypes {
    /**  子类型列表 */
    public Type[] value();
 
    public @interface Type {
        /** 子类型的Class */
        public Class<?> value();

        /**
         * 定义在类型上的逻辑名称 
         */
        public String name() default "";
    }
}

全局Default Typing机制

除了使用@JsonTypeInfo注解来实现多态数据绑定,还可以使用全局Default Typing机制。

DefaultTyping有四个选项:

  • JAVA_LANG_OBJECT: 当对象属性类型为Object时生效
  • OBJECT_AND_NON_CONCRETE: 当对象属性类型为Object或者非具体类型(抽象类和接口)时生效
  • NON_CONCRETE_AND+_ARRAYS: 同上, 另外所有的数组元素的类型都是非具体类型或者对象类型
  • NON_FINAL: 对所有非final类型或者非final类型元素的数组

对象引用与标识

@JsonManagedReference@JsonBackReference注解用于处理父/子关系并解决循环问题。

@JsonManagedReference

@JsonBackReference

@JsonIdentityInfo

用于指定在序列化/反序列化值时使用对象标识,例如,处理无限递归类型的问题。

@JsonIdentityReference

元注解

@JacksonAnnotation

注解在其他注解上,用于标识是jackson定义的注解。

@JacksonAnnotationsInside

AnnotationIntrospector

AnnotationIntrospector用于在处理数据时根据注解来自定义处理逻辑。默认的实现为NopAnnotationIntrospector,不做任何处理。

还有一个 JacksonAnnotationIntrospector,用于处理Jackson的注解逻辑。

Jackson使用进阶_第1张图片

AnnotationIntrospector抽象类实现了很多空方法,子类覆盖具体方法即可实现自定义逻辑。大部分方法都有一个类型为的Annotated参数。

Jackson使用进阶_第2张图片

示例:实现某个字段返回 **** 代替


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Person {
    @Mask
    private String name;
    private int age;
    private boolean male;

    private Address address;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Address {
    @Mask
    private String detail;
    private String post;
}

1、定义注解

@Target({ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface Mask {
    String value() default "****";
}

2、定义Serializer 用于序列化


class DataMaskingSerializer extends StdScalarSerializer<Object> {
    private String mask = "null";
    
    public DataMaskingSerializer(String mask) {
        super(String.class, false);
        this.mask = mask;
    }

    /**
    参数 o:当前用于序列化的对象,
    */
    @Override
    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        //只要加了注解,就用mask 代替
        jsonGenerator.writeString(mask);
    }
}

3、定义AnnotationIntrospector 用于指定注解要使用哪个Serializer


class PersonAnnotationIntrospector extends NopAnnotationIntrospector {

    @Override
    public Object findSerializer(Annotated am) {
        //找到指定注解,则使用指定的序列化器。
        Mask annotation = am.getAnnotation(Mask.class);
        if (annotation != null) {
            return new DataMaskingSerializer(annotation.value());
        }
        //返回null,则表示使用默认的(或者super)指定的序列化器
        return null;
    }
}

4、objectMapper设置 AnnotationIntrospector

        Address address = new Address("this is my home.", "410074");
        Person person = new Person("demon", 18, true, address);

        ObjectMapper objectMapper = new ObjectMapper();
        PersonAnnotationIntrospector ai = new PersonAnnotationIntrospector();
        objectMapper.setAnnotationIntrospector(ai);
        String s = objectMapper.writeValueAsString(person);
        System.out.println(s);

5、输出结果:

{"name":"****","age":18,"male":true,"address":{"detail":"****","post":"410074"}}

AnnotationIntrospectorPair

用于组合已有的AnnotationIntrospector 。可以设置主要 的和次要的。例如可以组合 JacksonAnnotationIntrospector ,用于满足现有的逻辑,再扩展自定义逻辑。



@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Person {
    @Mask
    private String name;

    @JsonFormat(pattern = "YYYY-MM-dd",shape = JsonFormat.Shape.STRING)
    Date birthday;
    private boolean male;

    private Address address;
}

仅自定义实现

ObjectMapper objectMapper = new ObjectMapper();
        AnnotationIntrospector ai = objectMapper.getSerializationConfig().getAnnotationIntrospector();
        AnnotationIntrospector newAi = AnnotationIntrospectorPair.pair(ai, new DataMaskingAnnotationIntrospector());
        objectMapper.setAnnotationIntrospector(newAi);
        return objectMapper;

假设只设置自定义AnnotationIntrospector,则默认的注解识别不了。



    public static void test() throws JsonProcessingException {
        Address address = new Address("this is my home.", "410074");
        Person person = new Person("demon",   Date.from(Instant.now()), true, address);

        ObjectMapper objectMapper = new ObjectMapper();
        PersonAnnotationIntrospector ai = new PersonAnnotationIntrospector();
        objectMapper.setAnnotationIntrospector(ai);
        String s = objectMapper.writeValueAsString(person);
        System.out.println(s);
    }

输出:

{"name":"****","birthday":1677122919273,"male":true,"address":{"detail":"****","post":"410074"}}

@JsonFormat未起作用。

组合已有实现

   public static void test() throws JsonProcessingException {

        Address address = new Address("this is my home.", "410074");
        Person person = new Person("demon",   Date.from(Instant.now()), true, address);

        ObjectMapper objectMapper = new ObjectMapper();
        PersonAnnotationIntrospector ai = new PersonAnnotationIntrospector();
		//组合多个实现
       //默认的是:### JacksonAnnotationIntrospector
        AnnotationIntrospector annotationIntrospector = objectMapper.getSerializationConfig().getAnnotationIntrospector();
        AnnotationIntrospector newAi = AnnotationIntrospectorPair.pair(annotationIntrospector, ai);

        objectMapper.setAnnotationIntrospector(newAi);
        String s = objectMapper.writeValueAsString(person);
        System.out.println(s);
    }

输出:

{"name":"****","birthday":"2023-02-23","male":true,"address":{"detail":"****","post":"410074"}}

JacksonAnnotationIntrospector

Jackson默认的实现。

支持的用于序列化注解:

  • JsonSerialize.class,
  • JsonView.class,
  • JsonFormat.class,
  • JsonTypeInfo.class,
  • JsonRawValue.class,
  • JsonUnwrapped.class,
  • JsonBackReference.class,
  • JsonManagedReference.class

支持的用于反序列化注解:

  • JsonDeserialize.class,
  • JsonView.class,
  • JsonFormat.class,
  • JsonTypeInfo.class,
  • JsonUnwrapped.class,
  • JsonBackReference.class,
  • JsonManagedReference.class,
  • JsonMerge.class // since 2.9

附录

参考

json中文官网:http://www.json.org/json-zh.html

json官网:http://www.json.org/

json参考手册:(译) JSON-RPC 2.0 规范(中文版)

Jackson官网地址:https://github.com/FasterXML/jackson

Jackson文档地址:https://github.com/FasterXML/jackson-docs

高级应用:https://www.baeldung.com/jackson-advanced-annotations

教程:

https://github.com/FasterXML/jackson-databind/

https://www.baeldung.com/jackson

https://mkyong.com/tutorials/java-json-tutorials/

https://jenkov.com/tutorials/java-json/index.html

https://www.logicbig.com/tutorials/misc/jackson.html

自定义注解

多态类型反序列化示例

use 属性 Id.CLASS


public class PTypeTest {
    public static void main(String[] args) {
        try {
            test();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void test() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        List<Shape> shapes = Lists.newArrayList(
                new Rectangle(10, 20),
                new Circle(100),
                new Square(50)
        );

        // serializing
        String jsonString = objectMapper.writeValueAsString(new Containers(shapes));
        System.out.println("jsonString=" + jsonString);
        System.out.println();

        // deserializing
        Containers containers = objectMapper.readValue(jsonString, Containers.class);
        System.out.println("containers=" + containers);
    }
}

@JsonTypeInfo(
        use = JsonTypeInfo.Id.CLASS,
        include = JsonTypeInfo.As.PROPERTY,
        property = "cn"
)
abstract class Shape {
    private String name;
    private int age;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Rectangle extends Shape {

    private int length;

    private int width;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Square extends Shape {
    private int sideLength;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Circle extends Shape {
    private int radius;
}

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Containers {
    private List<Shape> shapes;
}

输出:

属性的名字为 :className,属性值为类的全限定名称

jsonString={"shapes":[{"cn":"demon.research.objectmapper.Rectangle","length":10,"width":20},{"cn":"demon.research.objectmapper.Circle","radius":100},{"cn":"demon.research.objectmapper.Square","sideLength":50}]}
 
containers=demon.research.objectmapper.Containers@661972b0

@JsonTypeInfo 也可以放在属性上。

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
class Containers {
    @JsonTypeInfo(
            use = JsonTypeInfo.Id.CLASS,
            include = JsonTypeInfo.As.PROPERTY,
            property = "cn2"
    )
    private List<Shape> shapes;
}

输出:

jsonString={"shapes":[{"cn2":"demon.research.objectmapper.Rectangle","length":10,"width":20},{"cn2":"demon.research.objectmapper.Circle","radius":100},{"cn2":"demon.research.objectmapper.Square","sideLength":50}]}

属性上的注解优先级高于类上的注解。

use 属性 Id.MINIMAL_CLASS

@JsonTypeInfo(
        use = JsonTypeInfo.Id.MINIMAL_CLASS,
        include = JsonTypeInfo.As.PROPERTY,
        property = "cn"
)
abstract class Shape {
    private String name;
    private int age;
}

输出:

jsonString={"shapes":[{"cn":".Rectangle","length":10,"width":20},{"cn":".Circle","radius":100},{"cn":".Square","sideLength":50}]}

use 属性 Id.NAME


@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.PROPERTY,
        property = "cn"
)
abstract class Shape {
    private String name;
    private int age;
}

输出:

jsonString={"shapes":[{"cn":"Rectangle","length":10,"width":20},{"cn":"Circle","radius":100},{"cn":"Square","sideLength":50}]}

com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'Rectangle' as a subtype of [simple type, class demon.research.objectmapper.Shape]: known type ids = [] (for POJO property 'shapes')
 at [Source: (String)"{"shapes":[{"cn":"Rectangle","length":10,"width":20},{"cn":"Circle","radius":100},{"cn":"Square","sideLength":50}]}";

反序列化时,通过属性值识别不了类。需要加用于识别类的属性值。

@JsonSubTypes(
        { @JsonSubTypes.Type(value = Rectangle.class, name = "Rectangle")
        ,@JsonSubTypes.Type(value = Square.class, name = "Square")
        ,@JsonSubTypes.Type(value = Circle.class, name = "Circle")
        }
       
)
abstract class Shape {}

输出:

jsonString={"shapes":[{"cn":"Rectangle","length":10,"width":20},{"cn":"Circle","radius":100},{"cn":"Square","sideLength":50}]}

containers=demon.research.objectmapper.Containers@6356695f

include 属性 As.WRAPPER_OBJECT

现有属性作为一个包装对象的属性。包装属性的名称为 Name。


@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.WRAPPER_OBJECT,
        property = "cn"
)
@JsonSubTypes(
        { @JsonSubTypes.Type(value = Rectangle.class ,  name = "rectangle")
                ,@JsonSubTypes.Type(value = Square.class, name = "square")
                ,@JsonSubTypes.Type(value = Circle.class, name = "circle")
        }

)

@Getter
@Setter
abstract class Shape {
    public String type;
}

输出:

jsonString={"shapes":[{"rectangle":{"type":null,"length":10,"width":20}},{"circle":{"type":null,"radius":100}},{"square":{"type":null,"sideLength":50}}]}

include 属性 As.WRAPPER_ARRAY

现有对象与 类型区分属性(一个字符串对象) 作为2个对象,在一个数组里。

@JsonTypeInfo(
        use = JsonTypeInfo.Id.NAME,
        include = JsonTypeInfo.As.WRAPPER_ARRAY,
        property = "cn"
)
@JsonSubTypes(
        { @JsonSubTypes.Type(value = Rectangle.class ,  name = "rectangle")
                ,@JsonSubTypes.Type(value = Square.class, name = "square")
                ,@JsonSubTypes.Type(value = Circle.class, name = "circle")
        }

)

@Getter
@Setter
abstract class Shape {
    public String type;
}

输出:

jsonString={"shapes":[["rectangle",{"type":null,"length":10,"width":20}],["circle",{"type":null,"radius":100}],["square",{"type":null,"sideLength":50}]]}

@JsonAppend示例

使用attrs属性

@Data
@JsonAppend(attrs = {@JsonAppend.Attr(value = "age"),@JsonAppend.Attr(value = "sex")})
public class User {
    private String id;
    private String userName;
    private String passWord;
    private String email;
    private String nickName;
    private Date createTime;
}

{
  "id" : "999",
  "userName" : "小五",
  "passWord" : "888888",
  "email" : "[email protected]",
  "nickName" : null,
  "createTime" : 1675151635581,
    // 新增的2个属性。
  "age" : "20",
  "sex" : "男"
}

使用props属性

@Data
@JsonAppend(props = {@JsonAppend.Prop(value =TestWriter.class ,type = String.class,name = "idcard")}, prepend = true)
public class User {
    private String id;
    private String userName;
    private String passWord;
    private String email;
    private String nickName;
    private Date createTime;
}

@NoArgsConstructor
class TestWriter extends VirtualBeanPropertyWriter {


    private TestWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType) {
        super(propDef, contextAnnotations, declaredType);
    }


    @Override
    protected Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception {
        return "5002001564564565";
    }

    @Override
    public VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type) {
        return new TestWriter(propDef, declaringClass.getAnnotations(), type);
    }
}

{
    //增加了 idcard属性。
  "idcard" : "5002001564564565",
  "id" : "999",
  "userName" : "小五",
  "passWord" : "888888",
  "email" : "[email protected]",
  "nickName" : null,
  "createTime" : 1675151702894
}

你可能感兴趣的:(Java中间件,java,json,jackson,Introspector)