1. Jackson序列化注解(java -> json)
1.1 @JsonAnyGetter
可以灵活的将Map类型字段转换为标准的键值属性
bean
public class ExtendableBean { public ExtendableBean(String name) { this.name = name; this.properties = new HashMap<>(); } public String name; //public属性无序getter方法就能转换 private Map<String, String> properties; public void add(String key, String value){ properties.put(key,value); } @JsonAnyGetter public Map<String, String> getProperties() { return properties; } }
测试
//测试 @Test public void JsonAnyGetter() throws jsonProcessingException { ExtendableBean bean = new ExtendableBean("My bean"); bean.add("attr1", "val1"); bean.add("attr2", "val2"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"name":"My bean","attr2":"val2","attr1":"val1"} //使用: @JsonAnyGetter {"name":"My bean","properties":{"attr2":"val2","attr1":"val1"}} //不使用@JsonAnyGetter
1.2 @JsonGetter
标记字段的getter方法,同时可以指定序列化后json属性名
bean
@AllArgsConstructor //lombok注解 public class MyBean { public int id; //public属性无序getter方法就能转换 private String name; @JsonGetter("name") //序列化后属性名设置为name public String getTheName() { return name; } }
测试
@Test public void JsonGetter() throws jsonProcessingException { MyBean bean = new MyBean(1, "My bean"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"id":1,"name":"My bean"} //使用注解 @JsonGetter("name") {"id":1,"theName":"My bean"} //不使用注解
1.3 @JsonPropertyOrder
指定序列化后json属性顺序
bean
@AllArgsConstructor //lombok注解 //@JsonPropertyOrder(alphabetic=true) 可以设置按照字母顺序进行序列化 @JsonPropertyOrder({ "name", "id" }) public class OrderBean { public int id; public String name; }
测试
@Test public void JsonPropertyOrder() throws jsonProcessingException { OrderBean bean = new OrderBean(1, "Order bean"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"name":"Order bean","id":1} //使用注解 @JsonPropertyOrder({ "name", "id" }) {"id":1,"name":"Order bean"} //不使用注解
1.4 @JsonRawValue
标记字段原样序列化,该值不转义或引用
bean
@AllArgsConstructor //lombok注解 public class RawBean { public String name; @JsonRawValue public String json; }
测试
@Test public void JsonRawValue() throws jsonProcessingException { RawBean bean = new RawBean("My bean", "{\"attr\":false}"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"name":"My bean","json":{"attr":false}} //使用注解 @JsonRawValue {"name":"My bean","json":"{\"attr\":false}"} //不使用注解
1.5 @JsonValue
标记只序列化字段的值或者方法返回值(其他属性均被忽略),一个类中最多使用一个此注解
bean
@AllArgsConstructor //lombok注解 @Data //lombok注解 class ValueBean{ private int id; @JsonValue private String name; }
测试
@Test public void jsonValue() throws JsonProcessingException{ ValueBean bean = new ValueBean(1,"Value Bean"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
"Value Bean" //使用注解 {"id":1,"name":"Value Bean"} //不使用注解
1.6 @JsonRootName
在属性外层包装一个根节点属性,需要设置SerializationFeature.WRAP_ROOT_VALUE
bean
@AllArgsConstructor @Data //lombok注解 @JsonRootName(value = "root") //@JsonRootName(value = "user", namespace = "users") //2.4+新增namespace属性用于xml class RootBean{ private int id; private String name; }
测试
@Test public void jsonRootName() throws JsonProcessingException{ RootBean bean = new RootBean(1,"Root Bean"); String result = new ObjectMapper() .enable(SerializationFeature.WRAP_ROOT_VALUE) //需要设置此属性 (1) .writeValueAsString(bean); System.out.println(result); }
输出
{"root":{"id":1,"name":"Root Bean"}} //使用注解 {"id":1,"name":"Root Bean"} //不使用注解,且不设置属性 (1)
<-- 2.4+新增namespace属性用于xml,@JsonRootName(value = "user", namespace="users") --> <user xmlns="users"> <id xmlns="">1</id> <name xmlns="">John</name> <items xmlns=""/> </user>
1.7 @JsonSerialize
标识对指定字段进行自定义序列化 using 指定Class
bean
@AllArgsConstructor @Data //lombok注解 class SerializerBean{ private String name; @JsonSerialize(using = CustomDateSerializer.class) //该字段使用自定义序列化类 private LocalDate localDate; }
class CustomDateSerializer extends StdSerializer<LocalDate>{ public CustomDateSerializer() { this(null); //调用带参的构造函数 } public CustomDateSerializer(Class<LocalDate> t) { super(t); } @Override public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException { jsonGenerator.writeString(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); } }
测试
@Test public void jsonSerialize() throws JsonProcessingException{ SerializerBean bean = new SerializerBean("Serializer Bean", LocalDate.now()); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"name":"Serializer Bean","localDate":"2020-04-27"} //使用注解 { "name": "Serializer Bean", "localDate": { "year": 2020, "month": "APRIL", "monthValue": 4, "dayOfMonth": 27, "chronology": { "id": "ISO", "calendarType": "iso8601" }, "dayOfWeek": "MONDAY", "leapYear": true, "dayOfYear": 118, "era": "CE" } } //不使用注解
2. Jackson反序列化注解(json -> java)
2.1 @JsonCreator
标识反序列化时使用的构造函数,同时参数可以使用@JsonProperty(“theName”) String name 标识与json字段对应关系
bean
@Data //lombok注解 class CreatorBean{ private int id; private String name; @JsonCreator public CreatorBean( @JsonProperty("id") int id, @JsonProperty("theName") String name) { this.id = id; this.name = name; } }
测试
@Test public void jsonCreator() throws JsonProcessingException{ String json = "{\"id\":1,\"theName\":\"Creator bean\"}"; CreatorBean bean = new ObjectMapper() .readerFor(CreatorBean.class) //反序列化类型 .readValue(json); //json字符串 System.out.println(bean.toString()); }
输出
CreatorBean(id=1, name=Creator bean)
2.2 @JacksonInject
用于属性标识注入值,而非在json字符串中获取值
bean
@Data //lombok注解 class InjectBean{ @JacksonInject private int id; private String name; }
测试
@Test public void jacksonInject() throws IOException{ String json = "{\"name\":\"Inject bean\"}"; InjectableValues inject = new InjectableValues.Std() .addValue(int.class, 1); //添加值 InjectBean bean = new ObjectMapper().reader(inject) .forType(InjectBean.class) .readValue(json); System.out.println(bean); }
输出
InjectBean(id=1, name=Inject bean)
2.3 @JsonAnySetter
灵活的使用Map的key作为属性,反序列化时,json的属性将被简单的添加到map中
bean
@Data class AnySetterBean { public String name; private Map<String, String> properties = new HashMap<>(); @JsonAnySetter public void add(String key, String value){ properties.put(key,value); } }
测试
@Test public void jsonAnySetter() throws IOException { String json = "{\"name\":\"AnySetter bean\",\"attr2\":\"val2\",\"attr1\":\"val1\"}"; AnySetterBean bean = new ObjectMapper() .readerFor(AnySetterBean.class) .readValue(json); System.out.println(bean); }
输出
AnySetterBean(name=AnySetter bean, properties={attr2=val2, attr1=val1})
2.4 @JsonSetter
可以设置setter方法,指定与json不匹配的属性名赋值
bean
@Data //lombok注解 class SetterBean{ private int id; private String name; @JsonSetter(value = "theName") //指定使用json字符串中theName赋值 public void setName(String name) { this.name = name; } }
测试
@Test public void jsonSetter() throws IOException { String json = "{\"id\":1,\"theName\":\"Setter bean\"}"; SetterBean bean = new ObjectMapper() .readerFor(SetterBean.class) .readValue(json); System.out.println(bean); }
输出
SetterBean(id=1, name=Setter bean)
2.5 @JsonDeserialize
自定义反序列化: 实现StdDeserializer或是其父类JsonSerializer
bean
@Data //lombok注解 class DeserializerBean{ private String name; @JsonDeserialize(using = CustomDateDeserializer.class) private LocalDate localDate; }
//自定义反序列化 class CustomDateDeserializer extends StdDeserializer<LocalDate>{ public CustomDateDeserializer() { this(null); } protected CustomDateDeserializer(Class<?> vc) { super(vc); } @Override public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { return LocalDate.parse(jsonParser.getText(),DateTimeFormatter.ofPattern("yyyy-MM-dd")); } }
测试
@Test public void jsonDeserialize() throws IOException { String json = "{\"name\":\"party\",\"localDate\":\"2020-04-27\"}"; DeserializerBean bean = new ObjectMapper() .readerFor(DeserializerBean.class) .readValue(json); System.out.println(bean); }
输出
DeserializerBean(name=party, localDate=2020-04-27)
2.6 @JsonAlias
反序列化期间定义多个代替名称
bean
@Data class AliasBean { @JsonAlias({ "fName", "f_name" }) private String firstName; private String lastName; }
测试
@Test public void jsonAlias() throws IOException { String json = "{\"f_name\": \"John\", \"lastName\": \"Green\"}"; AliasBean bean = new ObjectMapper().readerFor(AliasBean.class).readValue(json); System.out.println(bean); }
输出
AliasBean(firstName=John, lastName=Green)
3. 兼容性注解
3.1 @JsonIgnoreProperties
用在类上,用来说明哪些属性在序列化/反序列化时忽略掉,可以看做是@JsonIgnore的批量操作
bean
@JsonIgnoreProperties({ "id" }) //序列化/反序列化时会忽略id属性 public class BeanWithIgnore { public int id; public String name; }
3.2 @JsonIgnore
作用在字段或者方法上,用来完全忽略字段或者方法对应的属性
bean
public class BeanWithIgnore { @JsonIgnore //忽略id属性 public int id; public String name; }
3.3. @JsonIgnoreType
作用于类,表示该类型的属性在序列化/反序列化时被忽略
bean
public class User { public int id; public Name name; //序列化/反序列化时该类型被忽略 @JsonIgnoreType public static class Name { public String firstName; public String lastName; } }
3.4 @JsonInclude
作用于类,序列化/反序列化时会排除 空值/null/设置的默认属性
bean
@JsonInclude(Include.NON_NULL) //排除null public class MyBean { public int id; public String name; }
3.5 @JsonAutoDetect
实现了成员属性可见性的语义,开启自动检测(可以检测私有属性)
bean
@AllArgsConstructor //lombok注解, 只有构造函数 //@Getter //不提供Getter方法 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) //等价于将private 设置为public class PrivateBean { private int id; private String name; //私有属性不提供Getter方法无法被序列化, //@JsonAutoDetect 使用注解设置可见性后可以访问private属性进行设置 }
测试
@Test public void jsonAutoDetect() throws JsonProcessingException { PrivateBean bean = new PrivateBean(1, "My bean"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"id":1,"name":"My bean"} //使用注解设置可见 //不使用注解则不能发现private属性
4. 处理多态类型的注解
bean
@ToString //lombok注解 class Zoo { public Animal animal; public Zoo() {} public Zoo(Animal animal) { this.animal = animal; } @JsonTypeInfo( //use 在序列化时标志出不同的类型用什么区分,用在反序列化时转换成响应的类型 //此处用定义的name区分 又如默认: JsonTypeInfo.Id.CLASS 完整类名区分 use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, //包含类型元数据的一种机制 property = "type" //property自定义的区分类型的id,默认是@Class //,visible = true //是否序列化/反序列化定义的type属性字段(此处是"type") // 如果为true则反序列化时json字符串中必须有type字段对应 ) @JsonSubTypes({ //添加所涉及的子类/实现类 @JsonSubTypes.Type(value = Dog.class, name = "dog"), @JsonSubTypes.Type(value = Cat.class, name = "cat") }) @ToString //lombok注解 public static class Animal { public String name; public Animal() { } public Animal(String name) { this.name = name; } } @JsonTypeName("dog") public static class Dog extends Animal { public Dog(String name) { super(name); } public double barkVolume; } @JsonTypeName("cat") public static class Cat extends Animal { boolean likesCream; public int lives; } }
测试
@Test //测试1 public void serializingPolymorphic() throws JsonProcessingException { Zoo.Dog dog = new Zoo.Dog("lacy"); Zoo zoo = new Zoo(dog); String result = new ObjectMapper().writeValueAsString(zoo); System.out.println(result); } @Test //测试2 public void deserializingPolymorphic() throws IOException { String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}"; Zoo zoo = new ObjectMapper().readerFor(Zoo.class).readValue(json); System.out.println(zoo); }
输出
{"animal":{"type":"dog","name":"lacy","barkVolume":0.0}} //测试1输出 Zoo(animal=Zoo.Animal(name=lacy)) //测试2输出
5. 一般注解
5.1 @JsonProperty
可以重新定义序列化/反序列化时对应的josn字符串属性名,有@JsonGetter 和 @JsonSetter的功能
bean
@AllArgsConstructor @NoArgsConstructor @ToString //lombok注解 class PropertyBean { public int id; private String name; @JsonProperty("name") public void setTheName(String name) { this.name = name; } @JsonProperty("name") public String getTheName() { return name; } }
测试
@Test public void jsonProperty() throws IOException { PropertyBean bean = new PropertyBean(1, "Property bean"); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); PropertyBean resultBean = new ObjectMapper().readerFor(PropertyBean.class).readValue(result); System.out.println(resultBean); }
输出
{"id":1,"name":"Property bean"} PropertyBean(id=1, name=Property bean)
5.2 @JsonFormat
定义序列化日期对象时的格式
bean
@AllArgsConstructor class FormatBean { public String name; @JsonFormat( shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") public Date eventDate; }
测试
@Test public void jsonFormat() throws Exception { FormatBean event = new FormatBean("party", new Date()); String result = new ObjectMapper().writeValueAsString(event); System.out.println(result); }
输出
{"name":"party","eventDate":"2020-04-28"}
5.3 @JsonUnwrapped
将对象扁平化处理(不要使用name:{}包裹对象属性)
bean
@AllArgsConstructor class UnwrappedUser { public int id; @JsonUnwrapped public Name name; @AllArgsConstructor public static class Name { public String firstName; public String lastName; } }
测试
@Test public void JsonUnwrapped() throws Exception { UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe"); UnwrappedUser user = new UnwrappedUser(1, name); String result = new ObjectMapper().writeValueAsString(user); System.out.println(result); }
输出
{"id":1,"firstName":"John","lastName":"Doe"} //使用注解@JsonUnwrapped {"id":1,"name":{"firstName":"John","lastName":"Doe"}} //不使用注解
5.4 @JsonView
可以指定哪些字段将被序列化/反序列化
bean
class Views { public static class Public {} public static class Internal extends Public {} } @AllArgsConstructor class ViewBean { @JsonView(Views.Public.class) public int id; @JsonView(Views.Public.class) public String itemName; @JsonView(Views.Internal.class) public String ownerName; }
测试
@Test public void jsonView() throws JsonProcessingException { ViewBean item = new ViewBean(2, "book", "John"); String result = new ObjectMapper() //设置视图: 此处序列化只序列化配置@JsonView(Views.Public.class)的字段及其父类 .writerWithView(Views.Public.class) .writeValueAsString(item); System.out.println(result); String result2 = new ObjectMapper() //设置视图: 只序列化配置@JsonView(Views.Internal.class) //因为Internal extends Public 因此也会序列化父类Public的配置 .writerWithView(Views.Internal.class) .writeValueAsString(item); System.out.println(result2); }
输出
{"id":2,"itemName":"book"} {"id":2,"itemName":"book","ownerName":"John"}
5.5 @JsonManagedReference, @JsonBackReference
处理类之间的循环引用
bean
@AllArgsConstructor class ItemWithRef { public int id; public String itemName; @JsonManagedReference //此处需要序列化 public UserWithRef owner; } //lombok注解:默认是private构造函数 //在此设置staticName = "of" //提供一个静态的of(int id,String name)方法, 参数为使用@NonNull的属性 @RequiredArgsConstructor(staticName = "of") class UserWithRef { @NonNull //lombok注解 public int id; @NonNull public String name; @JsonBackReference //序列化时不再序列化ItemWithRef对象中的UserWithRef属性 public List<ItemWithRef> userItems = new ArrayList<>(); public void addItem(ItemWithRef item) { userItems.add(item); } }
测试
@Test public void jacksonReferenceAnnotation() throws JsonProcessingException { UserWithRef user = UserWithRef.of(1, "John"); ItemWithRef item = new ItemWithRef(2, "book", user); user.addItem(item); String result = new ObjectMapper().writeValueAsString(item); System.out.println(result); }
输出
{"id":2,"itemName":"book","owner":{"id":1,"name":"John"}}
5.6 @JsonIdentityInfo
作用与类或者属性上,在序列化/反序列化时使用对象标识,通常解决循环引用问题
bean
//此类对象引用的其他类对象如果再引用到此类对象时只序列化标识属性值 @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") //使用对象的id值作为对象标识 ------(1) @AllArgsConstructor class ItemWithIdentity { public int id; public String itemName; public UserWithIdentity owner; //owner如何再引用到ItemWithIdentity对象则只序列化标识 } @JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") //使用对象的id值作为对象标识 ------(2) @RequiredArgsConstructor(staticName = "of") class UserWithIdentity { @NonNull public int id; @NonNull public String name; //userItems如何再引用到UserWithIdentity对象则只序列化标识 public List<ItemWithIdentity> userItems = new ArrayList<>(); public void addItem(ItemWithIdentity item) { userItems.add(item); } }
测试
@Test public void jsonIdentityInfo() throws JsonProcessingException { UserWithIdentity user = UserWithIdentity.of(1, "John"); ItemWithIdentity item = new ItemWithIdentity(2, "book", user); user.addItem(item); String result = new ObjectMapper().writeValueAsString(item); System.out.println(result); }
输出
{"id":2,"itemName":"book","owner":{"id":1,"name":"John","userItems":[2]}} //使用注解(1) (2) {"id":2,"itemName":"book","owner":{"id":1,"name":"John","userItems":[2]}}//只使用注解(1) {"id":2,"itemName":"book","owner":{"id":1,"name":"John","userItems":[{"id":2,"itemName":"book","owner":1}]}} //只使用注解(2) //注解(1) (2) 都不使用则报错
5.7 @JsonFilter
指定序列化期间使用的过滤器,类似@JsonIgnore
bean
@JsonFilter("myFilter") @AllArgsConstructor class FilterBean { public int id; public String name; }
测试
@Test public void jsonFilter() throws JsonProcessingException { FilterBean bean = new FilterBean(1, "Filter bean"); //创建过滤器 FilterProvider filters = new SimpleFilterProvider().addFilter( "myFilter", //添加过滤器名称 SimpleBeanPropertyFilter.filterOutAllExcept("name") //指定序列化的属性 //SimpleBeanPropertyFilter.serializeAllExcept("id")) //指定不序列化的属性 ); String result = new ObjectMapper() .writer(filters) //添加过滤器 .writeValueAsString(bean); System.out.println(result); }
输出
{"name":"Filter bean"}
6. 自定义Jackson注解
自定义注解
//注解的注解 @Retention(RetentionPolicy.RUNTIME) //jvm加载class文件后仍然保留注解 @JacksonAnnotationsInside //自定义Jackson注解 @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "name", "id", "dateCreated" }) @interface CustomAnnotation {}
bean
@AllArgsConstructor @CustomAnnotation //使用自定义注解 class CustomBean { public int id; public String name; public Date dateCreated; }
测试
@Test public void customAnnotation() throws JsonProcessingException { CustomBean bean = new CustomBean(1, "Custom bean", null); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); }
输出
{"name":"Custom bean","id":1}
7. Jackson MixIn Annotations动态过滤
可以在序列化时动态的过滤掉对象某些属性
bean
@AllArgsConstructor class Item { public int id; public String itemName; public User owner; class User{} } @JsonIgnoreType //类型忽略 class MyMixInForIgnoreType {}
测试
@Test public void mixInAnnotation() throws JsonProcessingException { Item item = new Item(1, "book", null); String result = new ObjectMapper().writeValueAsString(item); System.out.println(result); ObjectMapper mapper = new ObjectMapper(); //通过MyMixInForIgnoreType.class类型忽略,动态的设置忽略Item.User.class类型 mapper.addMixIn(Item.User.class, MyMixInForIgnoreType.class); result = mapper.writeValueAsString(item); System.out.println(result); }
输出
{"id":1,"itemName":"book","owner":null} {"id":1,"itemName":"book"}
8.禁用Jackson注解
设置禁用类的所有Jackson注解
bean
@AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) @JsonPropertyOrder({ "name", "id" }) class DisableBean { public int id; public String name; }
测试
@Test public void whenDisablingAllAnnotations_thenAllDisabled() throws IOException { DisableBean bean = new DisableBean(1, null); String result = new ObjectMapper().writeValueAsString(bean); System.out.println(result); result = new ObjectMapper().disable(MapperFeature.USE_ANNOTATIONS) //禁用Jackson注解 .writeValueAsString(bean); System.out.println(result); }
输出
{"id":1} {"id":1,"name":null}