我是靠谱客的博主 激情冥王星,最近开发中收集的这篇文章主要介绍Jackson注解详解引入依赖序列化注解反序列化注解属性相关注解类型处理注解通用注解自定义注解混入禁用注解,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

随着fastjson的壮大,漏洞也越来越多,是时候考虑下Jackson了,下面对Jackson近30个注解逐个解释。

引入依赖


<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>

序列化注解

@JsonAnyGetter

允许将map的字段变成标准字段.

看一个bean

public class Bean01 {
public String name;
private Map<String, String> properties;
public Bean01(String name, Map<String, String> properties) {
this.name = name;
this.properties = properties;
}
@JsonAnyGetter(enabled = false)
public Map<String, String> getProperties() {
return properties;
}
}

再看看测试:

@Test
public void testBean01() throws JsonProcessingException {
final Bean01 bean01 = new Bean01("jimo", new HashMap<>());
bean01.getProperties().put("k1", "v1");
bean01.getProperties().put("k2", "v2");
final String result1 = new ObjectMapper().writeValueAsString(bean01);
System.out.println(result1);
assertThat(result1, containsString("k1"));
assertThat(result1, containsString("v1"));
}

当enabled=false时,结果如下:

{
"name": "jimo",
"properties": {
"k1": "v1",
"k2": "v2"
}
}

当enabled=true时,结果如下:

{
"name": "jimo",
"k1": "v1",
"k2": "v2"
}

可以看到,map被拉平了。

@JsonGetter

public class Bean02 {
public int id;
private String name;
public Bean02(int id, String name) {
this.id = id;
this.name = name;
}
// @JsonGetter("name")
public String getTheName() {
return name;
}
}

看测试

@Test
public void testBean02() throws JsonProcessingException {
final Bean02 b = new Bean02(1, "jimo");
final String result = new ObjectMapper().writeValueAsString(b);
System.out.println(result);
assertThat(result, containsString("jimo"));
assertThat(result, containsString("name"));
assertThat(result, containsString("1"));
}

如果没有 @JsonGetter 的注解,得到的json是:

{
"id": 1,
"theName": "jimo"
}

加上后才是name:

{
"id": 1,
"name": "jimo"
}

@JsonPropertyOrder

就是指定生成的json字符串中属性的顺序,默认是按照声明顺序。

@JsonPropertyOrder(value = {"name", "id"})
public class Bean03 {
public int id;
public String name;
public Bean03(int id, String name) {
this.id = id;
this.name = name;
}
}

测试:

@Test
public void testBean03() throws JsonProcessingException {
final Bean03 b = new Bean03(1, "jimo");
final String s = new ObjectMapper().writeValueAsString(b);
assertEquals("{"name":"jimo","id":1}", s);
}

也支持按字母序排列: @JsonPropertyOrder(value = {"name", "id"}, alphabetic = true)

@JsonRawValue

直接将字符串里的json写成json格式.

public class Bean04 {
public String name;
@JsonRawValue
public String json;
public Bean04(String name, String json) {
this.name = name;
this.json = json;
}
}

测试:

@Test
public void testBean04() throws JsonProcessingException {
final Bean04 b = new Bean04("jimo", "{"attr":false}");
final String s = new ObjectMapper().writeValueAsString(b);
assertEquals("{"name":"jimo","json":{"attr":false}}", s);
}

结果:

{
"name": "jimo",
"json": {
"attr": false
}
}

JsonValue

public enum Bean05 {
USER1(1, "JIMO"), USER2(2, "HEHE");
private int id;
private String name;
Bean05(int id, String name) {
this.id = id;
this.name = name;
}
// @JsonValue
public String getName() {
return name;
}
}

看上面的枚举类,我们序列化时,其结果: “USER1”

@Test
public void testBean05() throws JsonProcessingException {
final String s = new ObjectMapper().writeValueAsString(Bean05.USER1);
// s== "USER1"
}

但是我们想只用name这个字段来代表枚举类,于是加上 @JsonValue.

得到: assertEquals(""JIMO"", s);

@JsonRootName

@JsonRootName(value = "user")
public class Bean06 {
public int id;
public String name;
public Bean06(int id, String name) {
this.id = id;
this.name = name;
}
}

测试:需要启用 WRAP_ROOT_VALUE

@Test
public void testBean06() throws JsonProcessingException {
final Bean06 b = new Bean06(1, "jimo");
final String s = new ObjectMapper().enable(SerializationFeature.WRAP_ROOT_VALUE).writeValueAsString(b);
assertEquals("{"user":{"id":1,"name":"jimo"}}", s);
}

可以看到user作为了根节点:

{"user":{"id":1,"name":"jimo"}}

@JsonSerialize

自定义序列化。

public class Bean07 {
public String name;
@JsonSerialize(using = MyLocalDateSerializer.class)
public LocalDate date;
public Bean07(String name, LocalDate date) {
this.name = name;
this.date = date;
}
}
public class MyLocalDateSerializer extends StdSerializer<LocalDate> {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public MyLocalDateSerializer() {
this(null);
}
protected MyLocalDateSerializer(Class<LocalDate> t) {
super(t);
}
@Override
public void serialize(LocalDate localDate, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(formatter.format(localDate));
}
}

测试:

@Test
public void testBean07() throws JsonProcessingException {
final Bean07 b = new Bean07("jimo", LocalDate.now());
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s);
}

在没有自定义序列化时:

{"name":"jimo","date":{"year":2020,"month":"SEPTEMBER","dayOfMonth":6,"monthValue":9,"chronology":{"id":"ISO","calendarType":"iso8601"},"dayOfWeek":"SUNDAY","dayOfYear":250,"era":"CE","leapYear":true}}

定义了之后:

{"name":"jimo","date":"2020-09-06"}

反序列化注解

@JsonCreator

用在构造方法或工厂方法,调节反序列化的过程。

比如,下面将 theName属性映射到 name 属性上:

public class Bean08 {
public int id;
public String name;
@JsonCreator
public Bean08(@JsonProperty("id") int id,
@JsonProperty("theName") String name) {
this.id = id;
this.name = name;
}
}

测试:

@Test
public void testBean08() throws JsonProcessingException {
String json = "{"id":1,"theName":"jimo"}";
final Bean08 b = new ObjectMapper().readValue(json, Bean08.class);
assertEquals("jimo", b.name);
}

JacksonInject

表示属性的值不从json里读,而是由注解指定。

public class Bean09 {
@JacksonInject
public int id;
public String name;
}

测试:

@Test
public void testBean09() throws IOException {
String json = "{"name":"jimo"}";
final InjectableValues.Std inject = new InjectableValues.Std().addValue(int.class, 1);
final Bean09 b = new ObjectMapper().reader(inject).readValue(json, Bean09.class);
assertEquals(1, b.id);
assertEquals("jimo", b.name);
}

JsonAnySetter

和JsonAnyGetter相对应,将json里的k-v映射回map:

public class Bean10 {
public String name;
private Map<String, String> properties;
public Bean10() {
this.properties = new HashMap<>();
}
@JsonAnySetter
public void add(String key, String value) {
properties.put(key, value);
}
public Map<String, String> getProperties() {
return properties;
}
}

测试:

@Test
public void testBean10() throws JsonProcessingException {
String json = "{"name":"jimo","attr2":"val2","attr1":"val1"}";
final Bean10 b = new ObjectMapper().readerFor(Bean10.class).readValue(json);
assertEquals("jimo", b.name);
assertEquals("val1", b.getProperties().get("attr1"));
assertEquals("val2", b.getProperties().get("attr2"));
}

JsonSetter

将任意方法变成一个setter方法

public class Bean11 {
public int id;
private String name;
@JsonSetter("name")
public void setTheName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

测试:

@Test
public void testBean11() throws JsonProcessingException {
String json = "{"id":1,"name":"jimo"}";
final Bean11 b = new ObjectMapper().readValue(json, Bean11.class);
assertEquals("jimo", b.getName());
}

JsonDeserialize

自定义反序列化

public class Bean12 {
public String name;
@JsonDeserialize(using = MyLocalDateDeserializer.class)
public LocalDate date;
}
public class MyLocalDateDeserializer extends StdDeserializer<LocalDate> {
public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
public MyLocalDateDeserializer() {
this(null);
}
protected MyLocalDateDeserializer(Class<?> vc) {
super(vc);
}
@Override
public LocalDate deserialize(JsonParser p, DeserializationContext ctx) throws IOException,
JsonProcessingException {
return LocalDate.parse(p.getText(), formatter);
}
}

测试:

@Test
public void testBean12() throws JsonProcessingException {
String json = "{"name":"jimo","date":"2020-09-06"}";
final Bean12 b = new ObjectMapper().readValue(json, Bean12.class);
assertEquals("2020-09-06", b.date.format(MyLocalDateDeserializer.formatter));
}

JsonAlias

别名

public class Bean13 {
@JsonAlias({"fName", "f_name"})
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}

测试:


@Test
public void testBean13() throws JsonProcessingException {
String json = "{"fName":"jimo","lastName":"hehe"}";
final Bean13 b = new ObjectMapper().readValue(json, Bean13.class);
assertEquals("jimo", b.getFirstName());
}

属性相关注解

@JsonIgnoreProperties

忽略某些注解, 用在类级别

@JsonIgnoreProperties({"id"})
public class Bean14 {
public int id;
public String name;
public Bean14(int id, String name) {
this.id = id;
this.name = name;
}
}

测试:

@Test
public void testBean14() throws JsonProcessingException {
final Bean14 b = new Bean14(1, "jimo");
final String s = new ObjectMapper().writeValueAsString(b);
assertThat(s, containsString("jimo"));
assertThat(s, not(containsString("id")));
}

JsonIgnore

也是忽略属性字段,用在字段级别

public class Bean15 {
@JsonIgnore
public int id;
public String name;
}

JsonIgnoreType

忽略某种类型的值。

public class Bean16 {
public int id;
public Name name;
public Bean16(int id, Name name) {
this.id = id;
this.name = name;
}
@JsonIgnoreType
public static class Name {
public String firstName;
public String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
}

测试:

@Test
public void testBean16() throws JsonProcessingException {
final Bean16.Name name = new Bean16.Name("jimo", "hehe");
final Bean16 b = new Bean16(1, name);
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s); // {"id":1}
}

JsonInclude

过滤某些字段,比如不为null的:

@JsonInclude(JsonInclude.Include.NON_NULL)
public class Bean17 {
public int id;
public String name;
public Bean17(int id, String name) {
this.id = id;
this.name = name;
}
}

测试:

@Test
public void testBean17() throws JsonProcessingException {
final Bean17 b = new Bean17(1, null);
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s); // {"id":1}
}

JsonAutoDetect

自动检测,也可以加一些规则

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.PROTECTED_AND_PUBLIC)
public class Bean18 {
public int id;
protected String name;
private int age;
public Bean18(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
}

测试:

@Test
public void testBean18() throws JsonProcessingException {
final Bean18 b = new Bean18(1, "jimo", 18);
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s); // {"id":1,"name":"jimo"}
}

类型处理注解

  • @JsonTypeInfo: 声明序列化时要包含的类型信息
  • @JsonSubTypes: 声明注解的字类型
  • @JsonTypeName: 给被注解的类定义一个逻辑类型名称

看例子:

一个动物园里有动物,动物的子类有狗和猫:

public class ZooRaw {
public Animal animal;
public ZooRaw() {
}
public ZooRaw(Animal animal) {
this.animal = animal;
}
public static class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public Animal() {
}
}
public static class Dog extends Animal {
public double barkVolume;
public Dog(String name) {
super(name);
}
}
public static class Cat extends Animal {
boolean likeCream;
public int lives;
public Cat(String name, int lives) {
super(name);
this.lives = lives;
}
public Cat() {
}
}
}

现在我们序列化动物园:

@Test
public void testZooEmpty() throws JsonProcessingException {
final ZooRaw.Dog dog = new ZooRaw.Dog("jimo");
final ZooRaw zoo = new ZooRaw(dog);
final String s = new ObjectMapper().writeValueAsString(zoo);
System.out.println(s); // {"animal":{"name":"jimo","barkVolume":0.0}}
}

没问题,但是当我们反序列化时,得到的就不是dog的实例了:

@Test
public void testCatEmptyDeserialize() throws JsonProcessingException {
String json = "{"animal":{"name":"lily"}}";
final ZooRaw zoo = new ObjectMapper().readValue(json, ZooRaw.class);
assertEquals("lily", zoo.animal.name);
assertEquals(ZooRaw.Animal.class, zoo.animal.getClass());
}

如何才能得到呢?使用上面的注解:

public class Zoo {
public Animal animal;
public Zoo() {
}
public Zoo(Animal animal) {
this.animal = animal;
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = Dog.class, name = "dog"),
@JsonSubTypes.Type(value = Cat.class, name = "cat")
})
public static class Animal {
public String name;
public Animal(String name) {
this.name = name;
}
public Animal() {
}
}
@JsonTypeName("dog")
public static class Dog extends Animal {
public double barkVolume;
public Dog(String name) {
super(name);
}
}
@JsonTypeName("cat")
public static class Cat extends Animal {
boolean likeCream;
public int lives;
public Cat(String name, int lives) {
super(name);
this.lives = lives;
}
public Cat() {
}
}
}

使用type字段区分类型,name区分同类型的不同类:

@Test
public void testZoo() throws JsonProcessingException {
final Zoo.Dog dog = new Zoo.Dog("jimo");
final Zoo zoo = new Zoo(dog);
final String s = new ObjectMapper().writeValueAsString(zoo);
System.out.println(s);
// {"animal":{"type":"dog","name":"jimo","barkVolume":0.0}}
}

可以看到多了 type 字段。

反序列化也ok:

@Test
public void testCatDeserialize() throws JsonProcessingException {
String json = "{"animal":{"name":"lily","type":"cat"}}";
final Zoo zoo = new ObjectMapper().readValue(json, Zoo.class);
assertEquals("lily", zoo.animal.name);
assertEquals(Zoo.Cat.class, zoo.animal.getClass());
}

通用注解

@JsonProperty

标注属性的

public class Bean19 {
public int id;
public String name;
public Bean19() {
}
public Bean19(int id, String name) {
this.id = id;
this.name = name;
}
@JsonProperty("name")
public void setTheName(String name) {
this.name = name;
}
@JsonProperty("name")
public String getTheName() {
return name;
}
}

测试:

@Test
public void testBean19() throws JsonProcessingException {
final Bean19 b = new Bean19(1, "jimo");
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s);
// {"id":1,"name":"jimo"}
final Bean19 bb = new ObjectMapper().readValue(s, Bean19.class);
assertEquals("jimo", bb.getTheName());
}

@JsonFormat

public class Bean20 {
public String name;
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd hh:mm:ss"
)
public Date date;
public Bean20(String name, Date date) {
this.name = name;
this.date = date;
}
public Bean20() {
}
}

测试:

@Test
public void testBean20() throws JsonProcessingException {
final Bean20 b1 = new Bean20("jimo", new Date());
final String s = new ObjectMapper().writeValueAsString(b1);
System.out.println(s);
// {"name":"jimo","date":"2020-09-08 01:16:55"}
final Bean20 b2 = new ObjectMapper().readValue(s, Bean20.class);
System.out.println(b2.date); // Tue Sep 08 09:16:55 CST 2020
}

@JsonUnwrapped

解构

public class Bean21 {
public int id;
@JsonUnwrapped
public Name name;
public Bean21(int id, Name name) {
this.id = id;
this.name = name;
}
public static class Name {
public String firstName;
public String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Name() {
}
}
}

测试:

@Test
public void testBean21() throws JsonProcessingException {
final Bean21.Name name = new Bean21.Name("jimo", "hehe");
final Bean21 b = new Bean21(1, name);
final String s = new ObjectMapper().writeValueAsString(b);
System.out.println(s);
// {"id":1,"firstName":"jimo","lastName":"hehe"}
}

@JsonView

就像数据库的视图一样,序列化和反序列化时指定哪些被view标记的序列化:

public class Bean22 {
@JsonView(Public.class)
public int id;
@JsonView(Public.class)
public String firstName;
@JsonView({Internal.class})
public String lastName;
public Bean22(int id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public class Public {
}
public class Internal extends Public {
}
}

测试:只序列化 Public 的:

@Test
public void testBean22() throws JsonProcessingException {
final Bean22 b = new Bean22(1, "jimo", "hehe");
final String s = new ObjectMapper()
.writerWithView(Bean22.Public.class)
.writeValueAsString(b);
System.out.println(s); // {"id":1,"firstName":"jimo"}
}

@JsonManagedReference,@JsonBackReference

处理父子关系循环,特别是递归情况下的序列化。

有一个类A:引用了B

public class A {
public int id;
public B b;
public A(int id, B b) {
this.id = id;
this.b = b;
}
}

类B:引用了A

public class B {
public int id;
public String name;
public List<A> items;
public B(int id, String name) {
this.id = id;
this.name = name;
items = new ArrayList<>();
}
}

我们来测试:

@Test
public void testRef() throws JsonProcessingException {
final B b = new B(2, "jimo");
final A a = new A(1, b);
b.items.add(a);
final String s = new ObjectMapper().writeValueAsString(a);
System.out.println(s);
}

得到一个栈溢出错误:

Caused by: java.lang.StackOverflowError

现在修改:

A.java

public class A {
public int id;
@JsonManagedReference
public B b;
public A(int id, B b) {
this.id = id;
this.b = b;
}
}

B.java

public class B {
public int id;
public String name;
@JsonBackReference
public List<A> items;
public B(int id, String name) {
this.id = id;
this.name = name;
items = new ArrayList<>();
}
}

结果为:

{"id":1,"b":{"id":2,"name":"jimo"}}

看起来结果里缺失了 items 字段,怎么解决看下面:

@JsonIdentityInfo

使用ID来标识对象。

A

@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class A {
public int id;
//
@JsonManagedReference
public B b;
public A(int id, B b) {
this.id = id;
this.b = b;
}
}

B

@JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id"
)
public class B {
public int id;
public String name;
//
@JsonBackReference
public List<A> items;
public B(int id, String name) {
this.id = id;
this.name = name;
items = new ArrayList<>();
}
}

结果:

{"id":1,"b":{"id":2,"name":"jimo","items":[1]}}

@JsonFilter

在序列化时指定过滤器

@JsonFilter("myFilter")
public class Bean23 {
public int id;
public String name;
public Bean23(int id, String name) {
this.id = id;
this.name = name;
}
}

测试

@Test
public void testBean23() throws JsonProcessingException {
final Bean23 b = new Bean23(1, "jimo");
final SimpleFilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name"));
final String s = new ObjectMapper().writer(filters).writeValueAsString(b);
assertEquals("{"name":"jimo"}", s);
}

自定义注解

@JacksonAnnotationInside

注解:排列列的顺序,忽略为null的

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"name", "id", "date"})
public @interface CustomOrderAnnotation {
}

定义bean

@CustomOrderAnnotation
public class Bean24 {
public int id;
public String name;
public Date date;
public Bean24(int id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
}

测试:

@Test
public void testBean24() throws JsonProcessingException {
final Bean24 b = new Bean24(1, "jimo", null);
final String s = new ObjectMapper().writeValueAsString(b);
assertEquals("{"name":"jimo","id":1}", s);
}

混入

使用addMixIn(target,source) 方法进行混入:

public class Bean25 {
public int id;
public String name;
public A a;
public Bean25(int id, String name, A a) {
this.id = id;
this.name = name;
this.a = a;
}
public class A {
}
@JsonIgnoreType
public class B {
}
}

测试:混入B类上的注解到A类后,A就被忽略了

@Test
public void testBean25() throws JsonProcessingException {
final Bean25 b1 = new Bean25(1, "jimo", null);
final String s = new ObjectMapper().writeValueAsString(b1);
assertEquals("{"id":1,"name":"jimo","a":null}", s);
final String s1 = new ObjectMapper().addMixIn(Bean25.A.class, Bean25.B.class).writeValueAsString(b1);
assertEquals("{"id":1,"name":"jimo"}", s1);
}

禁用注解

某些情况下想要禁止注解生效

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"name", "id"})
public class Bean26 {
public int id;
public String name;
public Bean26(int id, String name) {
this.id = id;
this.name = name;
}
}

测试:

@Test
public void testBean26() throws JsonProcessingException {
final Bean26 b = new Bean26(1, null);
final String s = new ObjectMapper().disable(MapperFeature.USE_ANNOTATIONS).writeValueAsString(b);
assertEquals("{"id":1,"name":null}", s);
}

最后

以上就是激情冥王星为你收集整理的Jackson注解详解引入依赖序列化注解反序列化注解属性相关注解类型处理注解通用注解自定义注解混入禁用注解的全部内容,希望文章能够帮你解决Jackson注解详解引入依赖序列化注解反序列化注解属性相关注解类型处理注解通用注解自定义注解混入禁用注解所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(77)

评论列表共有 0 条评论

立即
投稿
返回
顶部