Jackson注解大全

Jackson注解大全

Jackson是当前用的比较广泛的,用来序列化和反序列化json的Java开源框架。Jackson社区相对比较活跃,更新速度也比较快, 从Github中的统计来看,Jackson是最流行的json解析器之一,Spring MVC、SprigBoot的默认json解析器都是Jackson。

Jackson优点很多:

  1. Jackson 所依赖的jar包较少,简单易用。

  2. 与其他 Java 的 json 的框架 Gson 等相比,Jackson 解析大的 json 文件速度比较快。

  3. Jackson 运行时占用内存比较低,性能比较好

  4. Jackson 有灵活的 API,可以很容易进行扩展和定制。

在本文中,我们将学习如何使用Jackson提供的现有注解 ,如何创建自定义注解 ,以及如何禁用Jackson注解 。

1. Jackson序列化注解

1.1. @JsonAnyGetter

@JsonAnyGetter注解 可以灵活地把类型为Map的属性作为标准属性序列化到JSON字符串中,有如下特点:

  • 方法为非静态方法,并且方法不带任何参数,方法名没有特殊约定(随意定义方法名称)

  • 方法返回值必须是Map类型

  • 在一个实体类中只能用在一个方法上

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

编写测试用例:

@Test //@JsonAnyGetter  
public void jsonAnyGetter() throws JsonProcessingException {  
    ExtendableUser user = new ExtendableUser("Jack");  
    user.add("province", "四川");  
    user.add("city", "成都");  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
}  

测试结果如下:

{  
    "name":"Jack",  
    "province":"四川",  
    "city":"成都"  
}  

将ExtendableUser类的map中的属性提取出来当做了bean的标准属性序列化到JSON字符串中。在不改变Java类的前提下可以灵活地设置序列化后的JSON属性。

1.2. @JsonGetter

@JsonGetter注解 是@JsonProperty注解 的替代方法,用于将方法标记为getter方法。

在下面的例子中,我们指定getTheName()方法作为UserWithGetter实体的name属性的getter方法:

public class UserWithGetter {  
  
    private String name;  
    private int age;  
  
    public UserWithGetter() {  
  
    }  
  
    public UserWithGetter(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    @JsonProperty("name")  
    @JsonGetter("name")  
    public String getTheName() {  
        return name;  
    }  
  
    public int getAge() {  
        return age;  
    }  
}  

测试方法如下所示:

@Test //@JsonGetter  
public void jonGetter() throws JsonProcessingException {  
    UserWithGetter bean = new UserWithGetter("Jack",26);  
    String result = new ObjectMapper().writeValueAsString(bean);  
    System.out.println(result);  
}  

测试结果如下:

//不添加@JsonGetter("name")注解   
{"age":26,"theName":"Jack"}  
//添加@JsonGetter("name")注解   
{"age":26,"name":"Jack"}  

1.3. @JsonPropertyOrder

我们可以使用@JsonPropertyOrder注解 来指定序列化时各个属性的顺序。

定义User类,并自定义属性的顺序:

@JsonPropertyOrder({"name","age","id"})  
public class User {  
  
    private int id;  
    private String name;  
    private int age;  
    //省略 constructor  getters setters  
}  

测试JSON输出:

@Test //@JsonPropertyOrder  
public void jsonPropertyOrder() throws JsonProcessingException {  
    User user = new User(1, "Jack",28);  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
}  

测试结果按照@JsonPropertyOrder指定的顺序输出:

{  
    "name":"Jack",  
    "age":28,  
    "id":1  
}  

我们还可以使用_@JsonPropertyOrder(alphabetic = true)_按字母顺序对属性进行排序。在这种情况下,序列化输出结果是:

{  
    "age":28,  
    "id":1,  
    "name":"Jack"  
}  

1.4. @JsonRawValue

如果对象中某个字段的值是 JSON,在使用Jackson序列化时,输出的JSON会有问题,这时我们可以使用注解 @JsonRawValue将JSON值原样输出。

定义测试实体类:

public class RawUser {  
  
    private String name;  
  
    @JsonRawValue  
    private String address;  
  
   //省略 constructor  getters setters  
}  

编写测试用例:

@Test //@JsonRawValue  
public void jsonRawValue() throws JsonProcessingException {  
    String jsonString="{\"province\":\"广州\",\"city\":\"深圳\",\"area\":\"罗湖区\"}";  
    RawUser rawUser = new RawUser("Tom", jsonString);  
    String result = new ObjectMapper().writeValueAsString(rawUser);  
    System.out.println(result);  
}  

序列化输出结果为:

{  
    "name":"Tom",  
    "address":{  
        "province":"广州",  
        "city":"深圳",  
        "area":"罗湖区"  
    }  
}  

不添加@JsonRawValue注解时输出结果为:

{  
    "name":"Tom",  
    "address":"{"province":"广州","city":"深圳","area":"罗湖区"}"  
}  

我们还可以使用可选的布尔参数_值_来定义此注解 是否处于活动状态。

1.5. @JsonValue

@JsonValue可以用在字段或者字段对应的get方法上,当加上@JsonValue注解时,序列化返回的不再是JSON字符串,而是字段对应的值。一个类中只能有一个@JsonValue注解。

定义测试类UserJsonValue:

public class UserJsonValue {  
    private String name;  
    private int age;  
  
    @JsonValue  
    public String getName() {  
        return name;  
    }  
   //省略 constructor  getters setters  
}  

编写测试用例测试:

@Test //@JsonValue  
public void JsonValue() throws JsonProcessingException {  
    UserJsonValue user = new UserJsonValue("John", 27);  
    ObjectMapper mapper = new ObjectMapper();  
    String result = mapper.writeValueAsString(user);  
    System.out.println(result);  
}  

输出结果:

"John"  

1.6. @JsonRootName

正常情况下,我们定义一个User实体,并序列生成JSON字符串,输出结果如下:

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

但是,在某些情况下我们需要将JSON包装成如下形式:

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

针对以上问题,Jackson提供了很好的解决方案,即使用@JsonRootName注解。使用@JsonRootName注解指定要包装的root名称,并在ObjectMapper实例中启用包装。

定义包装实体:

@JsonRootName(value = "user")  
public class UserWithRoot {  
    private int id;  
    private String name;  
    //省略 constructor  getters setters  
}  

编写测试用例进行测试:

@Test //@JsonRootName  
public void jsonRootName() throws JsonProcessingException {  
    UserWithRoot user = new UserWithRoot(1, "John");  
  
    ObjectMapper mapper = new ObjectMapper();  
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);  
    String result = mapper.writeValueAsString(user);  
    System.out.println(result);  
}  

测试结果如下:

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

可选参数namespace,可用于XML等数据格式。如果添加它,就为xml前缀赋予了一个与某个命名空间相关联的限定名称:

@JsonRootName(value = "user", namespace="users")  
public class UserWithRootNamespace {  
    private int id;  
    private String name;  
    //省略 constructor  getters setters  
}  

序列化测试用例:

@Test //@JsonRootName namespace  
public void xmlRootNameWithNameSpace() throws JsonProcessingException {  
  
    UserWithRootNamespace author = new UserWithRootNamespace(1, "John");  
    ObjectMapper mapper = new XmlMapper();  
    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE)  
        .enable(SerializationFeature.INDENT_OUTPUT);  
    String result = mapper.writeValueAsString(author);  
  
    System.out.println(result);  
  
}  

使用_XmlMapper_对其进行序列化,输出结果如下:

<user xmlns="users">  
  <id xmlns="">1</id>  
  <name xmlns="">John</name>  
</user>  

1.7. @JsonSerialize

@JsonSerialize表示在序列化时要使用自定义序列化器。

我们定义一个需要序列化的实体Person,使用自定义序列化器:

public class Person {  
    private String name;  
    @JsonSerialize(using = CustomDateSerializer.class)  
    private Date birthday;  
   //省略 constructor  getters setters  
}  

自定义Jackson序列化器:

public class CustomDateSerializer extends StdSerializer<Date> {  
  
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
  
    public CustomDateSerializer() {  
        this(null);  
    }  
  
    public CustomDateSerializer(final Class<Date> t) {  
        super(t);  
    }  
  
    @Override  
    public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider ser) throws IOException {  
        jsonGenerator.writeString(formatter.format(date));  
    }  
}  

编写测试用例:

@Test  
public void jsonSerialize() throws JsonProcessingException, ParseException {  
  
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
  
    String toParse = "2020-05-19 02:30:00";  
    Date date = df.parse(toParse);  
    Person person = new Person("Tom", date);  
  
    String result = new ObjectMapper().writeValueAsString(person);  
    System.out.println(result);  
}  

输出结果如下:

{  
    "name":"Tom",  
    "birthday":"2020-05-19 02:30:00"  
}  

2. Jackson反序列化注解

2.1. @JsonCreator

JSON反序列化为java对象时,@JsonCreator注解用于定义构造函数。反序列化时,默认选择类的无参构造函数创建对象,当没有无参构造函数时会报错,@JsonCreator作用就是指定反序列化时用的无参构造函数。构造方法的参数前面需要加上@JsonProperty,否则会报错。

当我们需要反序列化某些与我们需要获取的目标实体不完全匹配的JSON时,此注解非常有用。

我们需要反序列化以下JSON:

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

但是,目标实体中没有_theName_字段,只有一个_name_字段。而我们不想更改实体本身,Jackson针对此问题提供了很好的解决方案。我们只要使用_@JsonCreator_注解 构造_函数_并同时使用_@JsonProperty_注解 构造函数参数:

public class UserWithCreator {  
    private int id;  
    private String name;  
  
    @JsonCreator  
    public UserWithCreator(@JsonProperty("id") int id, @JsonProperty("theName")String name) {  
        this.id = id;  
        this.name = name;  
    }  
    //省略 constructor  getters setters  
}  

编写测试用例,验证结果:

@Test //@JsonCreator  
public void jsonCreator() throws IOException {  
    String json = "{\"id\":1,\"theName\":\"Jack\"}";  
    ObjectMapper mapper = new ObjectMapper();  
    UserWithCreator user = mapper.readerFor(UserWithCreator.class).readValue(json);  
    System.out.println(user);  
}  

输出结果如下:

UserWithCreator{id=1, name='Jack'}  

2.2. @JacksonInject

在反序列化时,如果JSON中的字段少于目标java对象中的字段,被序列化后的对象将缺少字段设置为字段的默认值,而在某些需求中,我们希望自定义默认值,这时候我们就可以用到这个注解了,它的功能就是在反序列化的时候将没有的字段设置为我们期望的默认值。

定义反序列化实体类:

public class UserWithInject {  
    @JacksonInject  
    private int id;  
    private String name;  
    @JacksonInject  
    private String address;  
     //省略 constructor  getters setters  
}  

定义测试用例:

@Test //@JacksonInject  
public void jsonInject() throws IOException {  
    String json = "{\"name\":\"Jack\"}";  
    InjectableValues.Std injectableValues = new InjectableValues.Std();  
    injectableValues.addValue(String.class,"北京");  
    injectableValues.addValue(int.class, 1);  
    ObjectMapper mapper = new ObjectMapper();  
    UserWithInject user = mapper.reader(injectableValues).forType(UserWithInject.class).readValue(json);  
    System.out.println(user);  
}  

输出结果如下:

UserWithInject{id=1, name='Jack', address='北京'}  

2.3. @JsonAnySetter

一般情况下对象属性名都是确定的, 但有时候我们还需要给对象设定一些扩展属性, 这些扩展属性名称暂时不好确定, 通常使用 Map来存放这些扩展属性,针对此问题Jackson也提供了很好的解决方案。

要把JSON数据中的扩展属性反序列化到类的Map中, 需要在类中增加一个K/V的setter方法, 而且这个setter方法要加上@JsonAnySetter注解。

@JsonAnySette注意事项:

  1. 此注解用在非静态方法上,注解的方法必须有两个参数,第一个是json字段中的key,第二个是value,方法名随意。

  2. 此注解也可以用在Map对象属性上面,建议用在Map对象属性上面。

  3. 反序列化的时候将对应不上的字段全部放到Map里面。

使用_@JsonAnySetter_反序列化实体_ExtendableUser_:

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

如下是需要反序列化的JSON:

{  
    "name":"Jack",  
    "province":"四川",  
    "city":"成都"  
}  

编写测试用例测试:

@Test  
public void jsonAnySetter() throws IOException {  
    String json = "{\"name\":\"Jack\",\"province\":\"四川\",\"city\":\"成都\"}";  
    ObjectMapper mapper = new ObjectMapper();  
    ExtendableUser user = mapper.readerFor(ExtendableUser.class).readValue(json);  
    System.out.println(user);  
}  

测试结果如下:

ExtendableUser{name='Jack', properties={province=四川, city=成都}}  

2.4. @JsonSetter

@JsonSetter 标注于 setter 方法上,类似 @JsonProperty ,也可以解决 json 键名称和 java 对象 字段名称不匹配的问题。

我们将在_UserWithGetter_实体中将方法s etTheName()指定为_name_属性的setter方法:

public class UserWithGetter {  
  
    private String name;  
    private int age;  
  
    @JsonProperty("name")  
    @JsonSetter("name")  
    public void setTheName( String name) {  
        this.name = name;  
    }  
    //省略构造函数和其他方法  
}  

编写测试用例测试:

@Test  
public void jsonSetter() throws IOException {  
    String json = "{\"name\":\"Jack\",\"age\":28}";  
    ObjectMapper mapper = new ObjectMapper();  
    UserWithGetter user =mapper.readerFor(UserWithGetter.class).readValue(json);  
    System.out.println(user);  
}  
//输出结果:UserWithGetter{name='Jack', age=28}  

2.5. @JsonDeserialize

@JsonDeserialize注解指定使用自定义反序列化器。

定义反序列化类Person:

public class Person {  
    private String name;  
    @JsonDeserialize(using = CustomDateDeserializer.class)  
    private Date birthday;  
 //省略 constructor  getters setters  
}  

自定义反序列化器:

public class CustomDateDeserializer extends StdDeserializer<Date> {  
    private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
  
    public CustomDateDeserializer() {  
        this(null);  
    }  
  
    public CustomDateDeserializer(final Class<?> vc) {  
        super(vc);  
    }  
    @Override  
    public Date deserialize( JsonParser jsonparser,  DeserializationContext context) throws IOException {  
        String date = jsonparser.getText();  
        try {  
            return formatter.parse(date);  
        } catch (final ParseException e) {  
            throw new RuntimeException(e);  
        }  
    }  
}  

测试代码如下:

@Test  
public void jsonDeserialize() throws IOException {  
    String json = "{\"name\":\"Jack\",\"birthday\":\"2020-05-20 02:30:00\"}";  
  
    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");  
    ObjectMapper mapper = new ObjectMapper();  
    Person person =mapper.readerFor(Person.class).readValue(json);  
    System.out.println(person);  
    System.out.println(df.format(person.getBirthday()));  
}  

输出结果如下:

Person{name='Jack', birthday=Wed May 20 02:30:00 CST 2020}  
2020-05-20 02:30:00  

2.6 @JsonAlias

_@JsonAlias_注解定义在反序列化过程中给属性设置一个或者多个别名

定义AliasBean类来演示:

public class AliasUser {  
  
    @JsonAlias({ "fName", "f_name" })  
    private String firstName;  
  
    private String lastName;  
    //省略 constructor  getters setters  
}  

我们给AliasUser类的字段firstName,定义了两个别名fName和f_name。在反序列化的过程中,如果JSON字段中存在fName或者f_name,都会将值映射到AliasUser类的firstName字段中。

测试用例代码如下:

@Test  
public void jsonAlias() throws IOException {  
    String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";  
    ObjectMapper mapper = new ObjectMapper();  
    AliasUser aliasUser = mapper.readerFor(AliasUser.class).readValue(json);  
    System.out.println(aliasUser);  
}  
//输出结果:AliasUser{firstName='John', lastName='Green'}  

3. Jackson属性注解

3.1. @JsonIgnoreProperties

@JsonIgnoreProperties是一个类级别的注解 ,作用是将java对象序列化为JSON时,忽略的一个或多个属性。

以下示例,序列化时忽略UserWithIgnore类的属性_ID_:

@JsonIgnoreProperties({ "id" })  
public class UserWithIgnore {  
    private int id;  
    private String name;  
    //省略 constructor  getters setters  
}  

编写测试代码:

@Test  
public void jsonIgnoreProperties() throws JsonProcessingException {  
    UserWithIgnore bean = new UserWithIgnore(1, "Jack");  
    String result = new ObjectMapper().writeValueAsString(bean);  
}  

输出结果如下:

{"name":"Jack"}  

3.2. @JsonIgnore

@JsonIgnore是一个字段级别的注解 ,作用是在java对象序列化为JSON时,忽略此字段。

使用@JsonIgnore来忽略序列化的属性id:

public class UserWithIgnore {  
    @JsonIgnore  
    private int id;  
    private String name;  
    //省略 constructor  getters setters  
}  

测试代码如下:

@Test  
public void jsonIgnore() throws JsonProcessingException {  
    UserWithIgnore user = new UserWithIgnore(1, "Jack");  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
}  

输出结果如下:

{"name":"Jack"}  

3.3. @JsonIgnoreType

@JsonIgnoreType注解 要忽略注解 类型的所有属性。

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

测试代码如下:

@Test  
public void jsonIgnoreType() throws JsonProcessingException {  
    UserWithIgnoreType.Name name = new UserWithIgnoreType.Name("John", "Doe");  
    UserWithIgnoreType user = new UserWithIgnoreType(1, name);  
  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
}  

输出结果如下:

{"id":1}  

3.4. @JsonInclude

我们可以使用@JsonInclude排除具有empty/null/默认值的属性。

如下示例演示序列化时排除null值:

@JsonInclude(Include.NON_NULL)  
public class IncludeUser {  
    public int id;  
    public String name;  
    public int age;  
    public String address;  
 //省略 constructor  getters setters  
}  

测试:

@Test  
public void jsonInclude() throws JsonProcessingException {  
    IncludeUser user = new IncludeUser();  
    user.setId(1);  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
}  

输出结果如下:

{"id":1,"age":0}  

3.5. @JsonAutoDetect

我们定义的类中的所有属性由private修饰,不提供对应的get,set方法,如果按照默认的属性发现规则我们将无法序列化和反序列化类的字段(如果没有get,set方法,只有被public修饰的属性才会被发现)。这时,我们可以通过修改@JsonAutoDetect的fieldVisibility来调整自动发现级别,为了使字段被自动发现,我们需要将级别调整为ANY。

来看一个简单的示例:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)  
public class PrivateUser {  
    private int id;  
    private String name;  
  
    public PrivateUser() {  
  
    }  
  
    public PrivateUser(final int id, final String name) {  
        this.id = id;  
        this.name = name;  
    }  
}  

测试代码如下:

@Test  
public void jsonAutoDetect() throws JsonProcessingException {  
    PrivateUser bean = new PrivateUser(1, "Jack");  
  
    String result = new ObjectMapper().writeValueAsString(bean);  
    System.out.println(result);  
}  

输出结果:

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

4.Jackson常用注解

4.1. @JsonProperty

@JsonProperty 注解用于属性上,作用是把该属性的名称序列化为另外一个名称,例如将theName属性序列化为name,使用@JsonProperty("name")注解 。

@JsonProperty不仅仅是在序列化的时候有用,反序列化的时候也有用,比如有些接口返回的是json字符串,命名又不是标准的驼峰形式,在映射成对象的时候,在类的属性上加上@JsonProperty注解,里面写上返回的json串对应的名字即可。

定义实体类:

public class UserWithGetter {  
  
    private String name;  
    private int age;  
  
    @JsonProperty("name")  
    public void setTheName( String name) {  
        this.name = name;  
    }  
  
    @JsonProperty("name")  
    public String getTheName() {  
        return name;  
    }  
    //.....  
}  

测试并验证结果:

@Test  
public void jsonProperty() throws IOException {  
    UserWithGetter user = new UserWithGetter("Jack", 25);  
  
    String result = new ObjectMapper().writeValueAsString(user);  
    System.out.println(result);  
  
    UserWithGetter resultUser= new ObjectMapper().readerFor(UserWithGetter.class)  
        .readValue(result);  
    System.out.println(resultUser);  
}  

测试结果:

{"age":25,"name":"Jack"}  
UserWithGetter{name='Jack', age=25}  

4.2. @JsonFormat

@JsonFormat注解指定序列化日期和时间的格式

使用_@JsonFormat_来控制属性_birthday_的格式:

public class PersonWithFormat {  
    private String name;  
  
    @JsonFormat(shape = JsonFormat.Shape.BINARY, pattern = "yyyy-MM-dd hh:mm:ss")  
    private Date birthday;  
    //.....  
}  

测试:

@Test  
public void jsonFormat() throws JsonProcessingException, ParseException {  
    SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");  
    df.setTimeZone(TimeZone.getTimeZone("UTC"));  
  
    String toParse = "20-05-2020 02:30:00";  
    Date date = df.parse(toParse);  
    PersonWithFormat event = new PersonWithFormat("Jack", date);  
  
    String result = new ObjectMapper().writeValueAsString(event);  
    System.out.println(result);  
}  

输出结果:

{  
    "name":"Jack",  
    "birthday":"2020-05-20 02:30:00"  
}  

4.3. @JsonUnwrapped

@JsonUnwrapped定义了在序列化/反序列化时,将嵌套的对象属性,序列化到JSON的同一级。

定义UnwrappedUser实体:

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

序列化过程:

@Test  
public void jsonUnwrapped() throws JsonProcessingException {  
    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"}  

4.4. @JsonView

@JsonView注解作用是将java对象序列化为JSON时,过滤敏感字段或者不需要字段,使用步骤如下:

首先,声明视图:

public class Views {  
    public static class UserInfo {  
    }  
  
    public static class UserDetailInfo  extends UserInfo {  
    }  
}  

其次,定义序列化实体UserInfo:

public class UserInfo {  
    @JsonView(Views.UserInfo.class)  
    private String username;  
  
    @JsonView(Views.UserDetailInfo.class)  
    private String password;  
  
    @JsonView(Views.UserInfo.class)  
    private int age;  
    //.......  
}  

最后,测试:

@Test  
public void jsonView() throws JsonProcessingException {  
    UserInfo item = new UserInfo("Tom", "123456", 27);  
  
    String result = new ObjectMapper().writerWithView(Views.UserInfo.class)  
        .writeValueAsString(item);  
    System.out.println(result);  
  
    result = new ObjectMapper().writerWithView(Views.UserDetailInfo.class)  
        .writeValueAsString(item);  
    System.out.println(result);  
}  

输出结果:

{"username":"Tom","age":27}  
{"username":"Tom","password":"123456","age":27}  

4.5.@ JsonManagedReference,@ JsonBackReference

这两个注解通常配对使用, 可以解决两个不同类的属性的父子关系和循环引用。

@JsonBackReference标注的属性在序列化时,会被忽略。而@JsonManagedReference标注的属性则会被序列化。在序列化时,@JsonBackReference的作用相当于@JsonIgnore,此时可以没有@JsonManagedReference。但在反序列化时,如果没有@JsonManagedReference,则不会自动注入@JsonBackReference标注的属性(被忽略的父或子);如果有@JsonManagedReference,则会自动注入自动注入@JsonBackReference标注的属性。

定义_ItemWithRef_实体

public class ItemWithRef {  
    public int id;  
    public String itemName;  
  
    @JsonManagedReference  
    public UserWithRef owner;  
}  

和_UserWithRef_实体

public class UserWithRef {  
    public int id;  
    public String name;  
  
    @JsonBackReference  
    public List<ItemWithRef> userItems;  
}  

测试:

@Test  
public void jacksonReferenceAnnotation() throws JsonProcessingException {  
    UserWithRef user = new UserWithRef(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"}}  

4.6.@JsonIdentityInfo

@JsonIdentityInfo注解,作用于类或属性上,被用来在序列化/反序列化时为该对象或字段添加一个对象识别码,通常是用来解决循环嵌套的问题。定义两个实体,ItemWithIdentity实体

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")  
public class ItemWithIdentity {  
    public int id;  
    public String itemName;  
    public UserWithIdentity owner;  
}  

和_UserWithIdentity_实体:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")  
public class UserWithIdentity {  
    public int id;  
    public String name;  
    public List<ItemWithIdentity> userItems;  
}  

测试:

@Test  
public void  jsonIdentityInfo() throws JsonProcessingException {  
    UserWithIdentity user = new UserWithIdentity(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]}}  

4.7. @JsonFilter

@JsonFilter注解的作用是在序列化的过程中过滤掉指定的属性,类似于@JsonIgnore注解。但是当有一堆字段需要配置,而且整个项目都需要统一处理的时候,@JsonFilter比较适合。

定义实体,然后指向过滤器:

@JsonFilter("myFilter")  
public class UserWithFilter {  
    private int id;  
    private String name;  
    // ......  
}  

测试代码:

@Test  
public void jsonFilter() throws JsonProcessingException {  
    UserWithFilter bean = new UserWithFilter(1, "Jack");  
  
    //此过滤器的含义是除name属性外, 其他属性都被过滤掉(不序列化)  
    FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"));  
  
    String result = new ObjectMapper().writer(filters)  
        .writeValueAsString(bean);  
    System.out.println(result);  
}  

输出结果:

{"name":"Jack"}  

5.自定义Jackson注解

使用@JacksonAnnotationsInside创建自定义的Jackson注解 。

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

定义实体并使用新注解 :

@CustomAnnotation  
public class UserCustomAnnotation {  
    private int id;  
    private String name;  
    private int age;  
 //省略 constructor  getters setters  
}  

测试自定义注解 :

@Test //测试自定义注解   
public void customAnnotation() throws JsonProcessingException {  
    UserCustomAnnotation bean = new UserCustomAnnotation(1, "Jack", 28);  
    String result = new ObjectMapper().writeValueAsString(bean);  
    System.out.println(result);  
}  

序列化输出:

//添加注解 前  
{"id":1,"name":"Jack","age":28}  
//添加注解 后  
{"name":"Jack","age":28,"id":1}  

6.Jackson MixIn注解

Jackson MixIn注解用来忽略某个类型的所有字段。

首先,我们为要忽略的类型定义一个MixIn,并使用_@JsonIgnoreType进行_注解 。

@JsonIgnoreType  
public class MixInForIgnoreType {  
}  

然后,注册该mixin来忽略此类型:

mapper.addMixIn(Employee.class, MixInForIgnoreType.class);  

定义Company实体,忽略_Employee_类型的属性:

public class Company {  
    private int id;  
    private String companyName;  
    private Employee employee;  
    //省略 constructor  getters setters  
}  

测试并验证结果:

@Test  
public void mixInAnnotation() throws JsonProcessingException {  
    Company company = new Company(1, "小米", null);  
    String result = new ObjectMapper().writeValueAsString(company);  
    System.out.println(result);  
  
    ObjectMapper mapper = new ObjectMapper();  
    mapper.addMixIn(Employee.class, MixInForIgnoreType.class);  
  
    result = mapper.writeValueAsString(company);  
    System.out.println(result);  
}  

输出结果:

{"id":1,"companyName":"小米","employee":null}  
{"id":1,"companyName":"小米"}  

7.禁用Jackson注解

如何禁用所有Jackson注解?我们可以通过设置MapperFeature.USE_ANNOTATIONS来禁用实体类上的Jackson注解,创建如下实体类:

@JsonInclude(Include.NON_NULL)  
public class IncludeUser {  
    private int id;  
    private String name;  
    private int age;  
    private String address;  
    //省略 constructor  getters setters  
}  

测试并验证结果:

@Test  
public void disablingAllAnnotations() throws JsonProcessingException {  
  
    IncludeUser bean = new IncludeUser();  
  
    ObjectMapper mapper = new ObjectMapper();  
    mapper.disable(MapperFeature.USE_ANNOTATIONS);  
  
    String result = mapper.writeValueAsString(bean);  
    System.out.println(result);  
}  

禁用注解 之前输出结果:

{"id":0,"age":0}  

禁用注解 之后输出结果:

{"id":0,"name":null,"age":0,"address":null}  

posted @ 2023-01-30 16:30  明小子@  阅读(5)  评论(0)    收藏  举报