定义属性序列化时的名称。
@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
;
}
}
注解在类上,用于覆盖属性的定义。
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;
}
注解用于属性或者方法上,用来完全忽略被注释的字段和方法对应的属性。
放在getter
上也会禁用setter
,除非在setter上放置 @JsonProperty
。
注解在类上,用于忽略指定的属性。
@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;
}
注解在类上,用于忽略指定 类型 的属性。
用于排除值为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
;
}
用于生成字段的描述信息。
用于格式化日期/时间格式的数据。
@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
;
}
将对象扁平,即将属性实体的属性作为本对象的属性。
@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"
}
可以用于过滤属性。适用于在不同场景下,同一个字段是否输出。比如密码,在某些情况下返回,某些情况下不返回。
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
的属性,则忽略场景。
@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时,自动应用。
指定属性的一个或多个别名,只用于反序列化。即属性可以从多个JSON KEY中获取到值。可指定多个别名。
通过JSON字符串对已存在的对象实例进行更新。仅当属性值为null时,才会更新。
指定某个字段从注入赋值,而不是从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());
标记在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);
}
*/
}
为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;
}
}
当将JSON
读入对象时,应将此setter方法的名称与JSON数据中的属性名称匹配。如果Java类内部使用的属性名称与JSON文件中使用的属性名称不同,这个注解就很有用了。
class Book {
private String name;
//把JSON中的 bookName 属性值 读取 为 这个 方法。则设置了name的值。
@JsonSetter("bookName")
public void setName(String name){
this.name = name;
}
}
可以通过 @JsonEnumDefaultValue
注解为未知的枚举类型赋一个默认值来兜底,但要记得在 ObjectMapper 中手动开启该功能。
private enum Sex {
MAN,
WOMAN,
@JsonEnumDefaultValue
UNKNOWN
}
可以将Map用作要序列化为JSON的属性。
指定某个方法的返回值,用做JSON属性的值。
指定序列化时属性的顺序。
@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;
}
会将字符串形式的 JSON 也尝试序列化为对象。即如果属性是JSON字符串,则会序列化为JSON对象,而不再是个String属性。
不要由jackson序列化,而是调用 加此注解的方法的返回值作为JSON 串。比如 @JsonValue toJson()
方法。
指定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"}
}
在序列化时额外添加指定的属性。
@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 等。
标识注解,用在字段、getter、setter、构造函数参数上,用以指示是个多态类型。
@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;
}
用于指定子类用什么来进行区分。
com.foobar.Base
的具体类 com.foo.Impl
的id为.Impl
,具体类com.foo.impl.Impl2
的id为.impl.Impl2
。(注意前导点号)@JsonTypeIdResolver
解析。PROPERTY
一样的处理逻辑。在序列化时,TypeSerializer
不起作用。PROPERTY
类似,除了在层级结构的第一层,仅放在属性上而不是类上。property属性只有当:
use为:JsonTypeInfo.Id.CLASS
、JsonTypeInfo.Id.MINIMAL_CLASS
、JsonTypeInfo.Id.NAME
。
include为:JsonTypeInfo.As.PROPERTY、JsonTypeInfo.As.EXISTING_PROPERTY、JsonTypeInfo.As.EXTERNAL_PROPERTY
时才有效。
当
@JsonTypeInfo
在属性(字段,方法)上使用时,此注解适用于值。 当在集合类型(List,Map,Array)上使用时,它将应用于元素,而不是集合本身。 对于非集合类型,没有区别。
指定用于带注解的类的逻辑类型名称。如果在@JsonSubTypes.Type
中定义了 Name
属性,这优先使用它,否则使用@JsonTypeName
的值。
指定带注解类型的子类型。
@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 "";
}
}
除了使用@JsonTypeInfo
注解来实现多态数据绑定,还可以使用全局Default Typing
机制。
DefaultTyping有四个选项:
@JsonManagedReference
和@JsonBackReference
注解用于处理父/子关系并解决循环问题。
用于指定在序列化/反序列化值时使用对象标识,例如,处理无限递归类型的问题。
注解在其他注解上,用于标识是jackson定义的注解。
AnnotationIntrospector
用于在处理数据时根据注解来自定义处理逻辑。默认的实现为NopAnnotationIntrospector
,不做任何处理。
还有一个 JacksonAnnotationIntrospector
,用于处理Jackson的注解逻辑。
AnnotationIntrospector
抽象类实现了很多空方法,子类覆盖具体方法即可实现自定义逻辑。大部分方法都有一个类型为的Annotated
参数。
示例:实现某个字段返回 ****
代替
@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"}}
用于组合已有的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"}}
Jackson默认的实现。
支持的用于序列化注解:
支持的用于反序列化注解:
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}]]}
@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" : "男"
}
@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
}