Jackson 2.x 系列【8】注解大全篇四

352 阅读6分钟

有道无术,术尚可求,有术无道,止于术。

本系列 Jackson 版本 2.17.0

源码地址:https://gitee.com/pearl-organization/study-jaskson-demo

注解大全

🙈🙈🙈紧接上篇,接下来我们介绍jackson-databind模块提供的所有注解,到这里注解大全篇就结束了。🙈🙈🙈

2.35 @JsonSerialize

@JsonSerialize用于指定序列化器,相比于全局配置,可以针对特定的字段或类,提供了更细粒度的控制,

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonSerialize {
	// 指定序列化器
    Class<? extends JsonSerializer> using() default JsonSerializer.None.class;
	// 指定集合元素、Map键值对、数组元素序列化器
    Class<? extends JsonSerializer> contentUsing() default JsonSerializer.None.class;
	// 指定Map键序列化器
    Class<? extends JsonSerializer> keyUsing() default JsonSerializer.None.class;
	// 指定Null序列化器
    Class<? extends JsonSerializer> nullsUsing() default JsonSerializer.None.class;
	// 声明超类
    Class<?> as() default Void.class;
	// 将{@link java.util.Map}的键序列化为的具体类型
    Class<?> keyAs() default Void.class;
	// 将集合元素、Map键值对、数组元素序列化为的具体类型
    Class<?> contentAs() default Void.class;
	// 所使用的类型检测是动态的还是静态的:即,无论使用实际的运行时类型(动态),还是仅使用声明的类型(静态)
    Typing typing() default JsonSerialize.Typing.DEFAULT_TYPING;
	// 要使用哪个辅助对象将类型转换为某些内容
    Class<? extends Converter> converter() default Converter.None.class;
	// *类似于{@link#converter},但用于集合的值(List, arrays, Maps)
    Class<? extends Converter> contentConverter() default Converter.None.class;

@JsonSerialize中的using是最常用的,指定JsonSerializer类型的序列化器,可以自定义,也可以使用Jackson提供的序列化器:

image.png

例如之前我们在序列化LocalDateTime 时,就指定了LocalDateTimeSerializer

    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private LocalDateTime birthdayLocalDateTime;

2.36 @JsonDeserialize

@JsonDeserialize@JsonSerialize用法一致,用于反序列化:

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonDeserialize {
    Class<? extends JsonDeserializer> using() default JsonDeserializer.None.class;

    Class<? extends JsonDeserializer> contentUsing() default JsonDeserializer.None.class;

    Class<? extends KeyDeserializer> keyUsing() default KeyDeserializer.None.class;

    Class<?> builder() default Void.class;

    Class<? extends Converter> converter() default Converter.None.class;

    Class<? extends Converter> contentConverter() default Converter.None.class;

    Class<?> as() default Void.class;

    Class<?> keyAs() default Void.class;

    Class<?> contentAs() default Void.class;
}

2.37 @EnumNaming

EnumNamingStrategy接口用于在反序列化时,如何将枚举的字符串表示形式转换为用于映射的外部属性名称,@EnumNaming则用于指定使用哪个EnumNamingStrategy接口的实现类。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonNaming {
    Class<? extends PropertyNamingStrategy> value() default PropertyNamingStrategy.class;
}

2.38 @JsonNaming

@JsonNaming@EnumNaming类似,用于指定PropertyNamingStrategy

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonNaming {
    Class<? extends PropertyNamingStrategy> value() default PropertyNamingStrategy.class;
}

PropertyNamingStrategy用于声明属性名称生成策略,Jackson提供了很多默认策略:

image.png

示例,序列化时将所有属性名称转为首字母大写:

@JsonNaming(PropertyNamingStrategies.UpperCamelCaseStrategy.class)
public class JsonNamingVO {

    private Long id;

    private String name;
    // 省略........
}

执行序列化:

        JsonNamingVO jsonNamingVO=new JsonNamingVO();
        jsonNamingVO.setId(1455455612333L);
        jsonNamingVO.setName("测试");

        String jsonStrByJsonNamingVO = objectMapper.writeValueAsString(jsonNamingVO);
        System.out.println(jsonStrByJsonNamingVO);

输出结果如下:

{"Id":1455455612333,"Name":"测试"}

2.39 @JacksonStdImpl

@JacksonStdImpl作用于序列化器(JsonSerializer)、反序列化器(JsonDeserializer),标识当前是标准的Jackson实现的。

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JacksonStdImpl {
}

Jackson中很多负责序列化反序列化的类都标识了该注解:

在这里插入图片描述

2.40 @JsonAppend

@JsonAppend用于在序列化时添加虚拟属性(原本不属于对象中的属性)。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonAppend {
	// 虚拟属性名称
    Attr[] attrs() default {};
	// 虚拟值生成器
    Prop[] props() default {};

    boolean prepend() default false;
    // 省略........
}    

首先需要实现一个自定义的虚拟属性写类:

public class AddressVirtualBeanPropertyWriter extends VirtualBeanPropertyWriter {

    public AddressVirtualBeanPropertyWriter() {
    }

    private AddressVirtualBeanPropertyWriter(BeanPropertyDefinition propDef,
                                           Annotations contextAnnotations, JavaType declaredType) {
        super(propDef, contextAnnotations, declaredType);
    }
    @Override
    protected Object value(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws Exception {
        // 返回虚拟属性对应的值
        return "阿里巴巴";
    }

    @Override
    public VirtualBeanPropertyWriter withConfig(MapperConfig<?> mapperConfig, AnnotatedClass annotatedClass, BeanPropertyDefinition beanPropertyDefinition, JavaType javaType) {
        return new AddressVirtualBeanPropertyWriter(beanPropertyDefinition, null, javaType);
    }
}

当前类中只有idname属性:

@JsonAppend(props = @JsonAppend.Prop(name = "address", value = AddressVirtualBeanPropertyWriter.class))
public class JsonAppendVO {

    private Long id;

    private String name;
    // 省略........
}   

执行序列化:

        JsonAppendVO jsonAppendVO=new JsonAppendVO();
        jsonAppendVO.setId(1455455612333L);
        jsonAppendVO.setName("测试");

        String jsonStrByjsonAppendVO = objectMapper.writeValueAsString(jsonAppendVO);
        System.out.println(jsonStrByjsonAppendVO);

输出结果如下:

{"id":1455455612333,"name":"测试","address":"阿里巴巴"}

2.41 @JsonPOJOBuilder

在设计模式里,构建者模式是一种创建型设计模式,它旨在将复杂对象的创建过程与其表示分离,以便以灵活、可扩展和可维护的方式构建对象。@JsonPOJOBuilder作用于POJO类的构建类BuilderJackson会调用Builder.build()方法进行反序列化。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonPOJOBuilder {
    String DEFAULT_BUILD_METHOD = "build";
    String DEFAULT_WITH_PREFIX = "with";
	// 构建方法
    String buildMethodName() default "build";
	// 设置属性方法的前缀
    String withPrefix() default "with";
    // 省略........
}   

POJO也可以提供Builder用于构建对象,例如下面有一个简单的类:

示例如下:

@JsonDeserialize(builder = Dog.Builder.class)
public class Dog {

    private final String name;
    private final Integer age;

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    private Dog(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    @JsonPOJOBuilder
    static class Builder {
        String name;
        Integer age;

        Builder withName(String name) {
            this.name = name;
            return this;
        }

        Builder withAge(Integer age) {
            this.age = age;
            return this;
        }

        public Dog build() {
            System.out.println("使用build构建");
            return new Dog(name, age);
        }
    }
}

输出结果:

使用build构建
Dog{name='haha', age=2}

2.42 @JsonValueInstantiator

ValueInstantiatorJackson中声明的用于创建值对象的简单API@JsonValueInstantiator则是指定类使用哪个ValueInstantiator实现类。

@Target({ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonValueInstantiator {
	// ValueInstantiator实现类
    Class<? extends ValueInstantiator> value();
}

示例,实现了一个ValueInstantiator,并指定了一个默认对象:

@JsonValueInstantiator(MyValueInstantiator.class)
public class ValueInstantiatorVO {

    protected final String a;
    protected final int b;

    public ValueInstantiatorVO(String a, int b) {
        this.a = a;
        this.b = b;
    }

    @Override
    public String toString() {
        return "ValueInstantiatorVO{" +
                "a='" + a + '\'' +
                ", b=" + b +
                '}';
    }
}

public class MyValueInstantiator extends ValueInstantiator.Base {
    public MyValueInstantiator() {
        super(Object.class);
    }

    @Override
    public String getValueTypeDesc() {
        return ValueInstantiatorVO.class.getName();
    }

    @Override
    public boolean canCreateUsingDefault() { return true; }

    @Override
    public ValueInstantiatorVO createUsingDefault(DeserializationContext ctxt) {
        return new ValueInstantiatorVO("哈哈", 3);
    }
}

执行反序列化:

        String strByValueInstantiatorVO = "{}";
        ValueInstantiatorVO valueInstantiatorVO =objectMapper.readValue(strByValueInstantiatorVO, ValueInstantiatorVO.class);
        System.out.println(valueInstantiatorVO);

输出结果:

ValueInstantiatorVO{a='哈哈', b=3}

2.43 @JsonTypeResolver

@JsonTypeResolver用于指定TypeResolverBuilder(类型解析器构建者),可以在序列化时显示属性的类型。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeResolver {
    Class<? extends TypeResolverBuilder<?>> value();
}

示例如下:

public class Data {
    private Long key;

    @JsonCreator
    Data(@JsonProperty("key") Long key) {
        this.key = key;
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
    @JsonTypeResolver(MyTypeResolverBuilder.class)
    public long key() {
        return key;
    }

    static class MyTypeResolverBuilder extends StdTypeResolverBuilder {
        // 允许显示类型
        @Override
        protected boolean allowPrimitiveTypes(MapperConfig<?> config,
                                              JavaType baseType) {
            return true;
        }
    }
}

执行序列化:

        Data data = new Data(1L);
        Map<String, Object> mapData = new HashMap<>();
        mapData.put("longInMap", 2L);
        mapData.put("longAsField", data);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
        String strByJsonTypeResolver = objectMapper.writeValueAsString(mapData);
        System.out.println(strByJsonTypeResolver);

输出结果:

{
  "longInMap" : 2,
  "longAsField" : {
    "key" : [ "java.lang.Long", 1 ]
  }
}

2.44 @JsonTypeIdResolver

@JsonTypeIdResolver(自定义如何生成和解析类型信息)通常需要配合@JsonTypeInfo(指定序列化时包含的类型信息)注解一起使用,用于解决在序列化和反序列化过程中可能出现的类型识别问题。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonTypeIdResolver {
    Class<? extends TypeIdResolver> value();
}

这里贴一个官方示例:

@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.WRAPPER_OBJECT)
@JsonTypeIdResolver(CustomBean.CustomResolver.class)
public abstract class CustomBean {

    static class CustomBeanImpl extends CustomBean {
        public int x;

        public CustomBeanImpl() { }
        public CustomBeanImpl(int x) { this.x = x; }
    }

    static class CustomResolver extends TestCustomResolverBase {
        // yes, static: just for test purposes, not real use
        static List<JavaType> initTypes;

        public CustomResolver() {
            super(CustomBean.class, CustomBeanImpl.class);
        }

        @Override
        public void init(JavaType baseType) {
            if (initTypes != null) {
                initTypes.add(baseType);
            }
        }
    }

    static class TestCustomResolverBase extends TypeIdResolverBase {
        protected final Class<?> superType;
        protected final Class<?> subType;

        public TestCustomResolverBase(Class<?> baseType, Class<?> implType) {
            superType = baseType;
            subType = implType;
        }

        @Override
        public JsonTypeInfo.Id getMechanism() {
            return JsonTypeInfo.Id.CUSTOM;
        }

        @Override
        public String idFromValue(Object value) {
            if (superType.isAssignableFrom(value.getClass())) {
                return "*";
            }
            return "unknown";
        }

        @Override
        public String idFromValueAndType(Object value, Class<?> type) {
            return idFromValue(value);
        }

        @Override
        public void init(JavaType baseType) {
        }

        @Override
        public JavaType typeFromId(DatabindContext context, String id) {
            if ("*".equals(id)) {
                return TypeFactory.defaultInstance().constructType(subType);
            }
            return null;
        }

        @Override
        public String idFromBaseType() {
            return "xxx";
        }
    }
}

执行序列化和反序列化:

        List<JavaType> types = new ArrayList<JavaType>();
        CustomBean.CustomResolver.initTypes = types;
        String jsonByTypeIdResolver = objectMapper.writeValueAsString(new CustomBean[] { new CustomBean.CustomBeanImpl(28) });
        System.out.println(jsonByTypeIdResolver);

        types = new ArrayList<JavaType>();
        CustomBean.CustomResolver.initTypes = types;
        CustomBean[] result = objectMapper.readValue(jsonByTypeIdResolver, CustomBean[].class);
        System.out.println(result);

结果输出:

[ {
  "*" : {
    "x" : 28
  }
} ]
[Lcom.pearl.jacksoncore.demo.databind.anno.CustomBean;@fbd1f6