Jackson注释的使用

在这里插入图片描述

Jackson提供了一系列注解,可以使用这些注解来设置将JSON读入对象的方式或从对象生成什么JSON的方式,下面介绍一些常用的注解。

3.1 序列化

@JsonAnyGetter

  @JsonAnyGetter 注解运行可以灵活的使用Map类型的作为属性字段,允许getter方法返回Map,该Map然后用于以与其他属性类似的方式序列化JSON的其他属性。通过序列化该实体Bean,我们将会得到Map属性中的所有Key作为属性值,测试序列化代码如下

import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) 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);
	}
}

class ExtendableBean {
	public String name;
	private Map<String, String> properties;

	@JsonAnyGetter
	public Map<String, String> getProperties() {
		return properties;
	}

	public ExtendableBean(String name) {
		this.name = name;
		this.properties = new HashMap<String, String>();
	}

	public void add(String key, String value) {
		this.properties.put(key, value);
	}
}

最终输出结果如下

{
    "name":"My bean",
    "attr2":"val2",
    "attr1":"val1"
}

如果不使用**@JsonAnyGetter**注解,那么最终序列化结果将会在properties属性下面,结果如下:

{
    "name": "My bean",
    "properties": {
        "attr2": "val2",
        "attr1": "val1"
    }
}

@JsonRawValue

@JsonRawValue注解可以指定字符串属性类为json,如下代码:

import java.io.IOException;
import java.text.ParseException;
import com.fasterxml.jackson.annotation.JsonRawValue;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) throws IOException, ParseException {
		RawBean bean = new RawBean("My bean", "{\"attr\":false}");
		String result = new ObjectMapper().writeValueAsString(bean);
		System.out.println(result);
	}
}

class RawBean {
	public String name;
	@JsonRawValue
	public String json;

	public RawBean(String name, String json) {
		super();
		this.name = name;
		this.json = json;
	}
}

最终使用@JsonRawValue序列化结果如下:

{
    "name":"My bean",
    "json":{
        "attr":false
    }
}

没有使用@JsonRawValue序列化结果如下:

{
    "name":"My bean",
    "json":"{\"attr\":false}"
}

@JsonRootName

  @JsonRootName注解旨在给当前序列化的实体对象加一层包裹对象,允许在JSON上指定根节点。

@data
public class RootUser {
 
    private String name;
    private String title;
 
    public RootUser(String name, String title) {
        this.name = name;
        this.title = title;
    }
}

在上面的实体类中,正常情况下,如果要序列号RootUser对象,其结果格式为:

{
    "name": "name1",
    "title": "title1"
}

在RootUser加上**@JsonRootName** 注解后,该类改动如下:

@JsonRootName(value = "root")
public class RootUser {
 
    private String name;
    private String title;
 
    public RootUser(String name, String title) {
        this.name = name;
        this.title = title;
    }
}

  @JsonRootName 仅用于指定 JSON 根属性的名称,只有当SerializationFeature.WRAP_ROOT_VALUE、DeserializationFeature.UNWRAP_ROOT_VALUE 启用时才有效。若只开启了 Feature 功能但未使用 @JsonRootName 注解,默认会使用类名作为 RootName。

ObjectMapper objectMapper=new ObjectMapper();
// 启用 SerializationFeature.WRAP_ROOT_VALUE
objectMapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
// 启用 DeserializationFeature.UNWRAP_ROOT_VALUE
objectMapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
String result=objectMapper.writeValueAsString(new RootUser("name1","title1"));

最终序列化JSON结果如下:

{
    "root": {
        "name": "name1",
        "title": "title1"
    }
}

@JsonSerialize

  实际开发中,一定遇到过这样的问题:前端显示和后台存储数据单位不统一,而且各有各自的理由,统一不了,那就只能由后端转换。每次返回给前端时再转换一遍,返回给前端的json数据,在后端里定义的往往是一个对象,如何做到优雅的转换呢?例如,Double类型的数据返回值转换成字符串,只需两步操作:

  1. 写一个负责转换的类,里面写好规则。
public class CustomDoubleSerialize extends JsonSerializer<Double> {

	@Override
	public void serialize(Double value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
		BigDecimal d = new BigDecimal(value.toString());
		gen.writeString(d.stripTrailingZeros().toPlainString());
	}
}
  1. 在实体类上需要装换的字段上加上注解
/**
 * 金额
 */
@JsonSerialize(using = CustomDoubleSerialize.class)
private Double amount;

又例如,假设某布尔值false和true,使其分别为0和1。

  1. 写一个负责转换的类,里面写好规则:将序列的真值序列化为1,将假值序列化为0。
public class OptimizedBooleanSerializer extends JsonSerializer<Boolean> {
 
    @Override
    public void serialize(Boolean aBoolean, JsonGenerator gen, SerializerProvider provider) throws IOException {
        if(aBoolean){
            jsonGenerator.writeNumber(1);
        } else {
            jsonGenerator.writeNumber(0);
        }
    }
}
  1. 在实体类上需要装换的字段上加上注解
@JsonSerialize(using = OptimizedBooleanSerializer.class)
public boolean enabled = false;

注:@JsonSerialize注解,主要应用于数据转换,该注解作用在该属性的getter方法上

@JsonGetter

  @JsonGetter 注解用于告诉Jackson,应该通过调用getter方法而不是通过直接字段访问来获取某个字段值。 如果您的Java类使用getter和setter名称,则@JsonGetter注解很有用。

import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) throws JsonProcessingException {
		ObjectMapper mapper = new ObjectMapper();
		Student student = new Student("Mark", 1);
		String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(student);
		System.out.println(jsonString);

	}
}

class Student {
	private String name;
	private int rollNo;

	public Student(String name, int rollNo) {
		this.name = name;
		this.rollNo = rollNo;
	}

	@JsonGetter("studentName")
	public String getName() {
		return name;
	}

	public int getRollNo() {
		return rollNo;
	}
}

使用 @JsonGetter 输出如下结果:

{
  "rollNo" : 1,
  "studentName" : "Mark"
}

而没有使用 @JsonGetter 输出如下结果:

{
  "name" : "Mark",
  "rollNo" : 1
}

3.2 反序列化

@JsonCreator

  @JsonCreator 用于告诉Jackson该Java对象具有一个构造函数,该构造函数可以将JSON对象的字段与Java对象的字段进行匹配。配合@JsonProperty注解能到达在反序列化实体对象时,指定不变更属性名称的效果。例如有如下JSON:

{
    "id":1,
    "theName":"My bean"
}

在实体类中,我们没有属性名称是theName,但我们想把theName属性反序列化时赋值给name,此时实体类对象结构如下:

public class BeanWithCreator {
	public int id;
	public String name;

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

在BeanWithCreator的构造函数中添加@JsonCreator注解,并且配合@JsonProperty注解进行属性指向,最终反序列化代码如下:

import java.io.IOException;
import java.text.ParseException;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) throws IOException, ParseException {
		String json = "{\"id\":1,\"theName\":\"My bean\"}";

		BeanWithCreator bean = new ObjectMapper().readerFor(BeanWithCreator.class).readValue(json);
		System.out.println(new ObjectMapper().writeValueAsString(bean));
	}
}

class BeanWithCreator {
	public int id;
	public String name;

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

@JsonAnySetter

  @JsonAnySetter 表示Jackson为JSON对象中所有无法识别的字段调用相同的setter方法, “无法识别”是指尚未映射到Java对象中的属性或设置方法的所有字段。@JsonAnySetter注解可以将来源JSON最终转化为Map类型的属性结构。

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) {
		ObjectMapper mapper = new ObjectMapper();
		String jsonString = "{\"RollNo\" : \"1\",\"Name\" : \"Mark\"}";
		try {
			Student student = mapper.readerFor(Student.class).readValue(jsonString);
			System.out.println(student.getProperties());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class Student {
	private Map<String, String> properties;

	public Student() {
		properties = new HashMap<>();
	}

	public Map<String, String> getProperties() {
		return properties;
	}

	@JsonAnySetter
	public void add(String property, String value) {
		properties.put(property, value);
	}
}

@JsonSetter

  @JsonSetter注解是@JsonProperty的替代注解,用于告诉Jackson将特定方法标记为setter方法。当将JSON读入对象时,应将此setter方法的名称与JSON数据中的属性名称匹配。当我们需要读取一些JSON数据时,但是目标实体类与该数据的属性名称不同,该注解是非常有用的。

import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonTester {
	public static void main(String args[]) throws JsonProcessingException {
		String json = "{\"id\":1,\"name\":\"My bean\"}";
		ObjectMapper mapper = new ObjectMapper();
		MyBean myBean = mapper.readerFor(MyBean.class).readValue(json);
		System.out.println(mapper.writeValueAsString(myBean));
	}
}

class MyBean {
	private int id;
	private String thename;

	/**
	 * 通过指定setTheName作为属性name的setter方法,反序列化时可以达到最终效果
	 */
	@JsonSetter("name")
	public void setTheName(String name) {
		this.thename = name;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getTheName() {
		return thename;
	}
}

@JsonDeserialize

  @JsonDeserialize注解和序列化注解@JsonSerialize的效果是一致的,作用与反序列化时,针对特定的字段,存在差异化的发序列化效果。首先,需要将@JsonDeserialize注解添加到要为其使用自定义反序列化器的字段,如下所示

public class PersonDeserialize {
 
    public long id = 0;
    public String  name = null;
 
    @JsonDeserialize(using = OptimizedBooleanDeserializer.class)
    public boolean enabled = false;
}

其次,这是@JsonDeserialize注解中引用的OptimizedBooleanDeserializer类的实例

public class OptimizedBooleanDeserializer
    extends JsonDeserializer<Boolean> {
 
    @Override
    public Boolean deserialize(JsonParser jsonParser,
            DeserializationContext deserializationContext) throws
        IOException, JsonProcessingException {
 
        String text = jsonParser.getText();
        if("0".equals(text)) return false;
        return true;
    }
}

请注意,OptimizedBooleanDeserializer类使用通用类型Boolean扩展了JsonDeserializer。 这样做会使deserialize()方法返回一个布尔对象。 如果要反序列化其他类型(例如java.util.Date),则必须在泛型括号内指定该类型。

3.3 属性注解

@JsonIgnore

  Jackson注解 @JsonIgnore 用来告诉 Jackson 在处理时忽略Java对象的某个属性(字段),在将JSON读取到Java对象中以及将Java对象写入JSON时,都将忽略该属性。

@Data
public class SellerInfoEntity {
 
    private String id;
    private String username;
    private String password;
    
    @JsonIgnore
    private Timestamp createTime;
    @JsonIgnore
    private Timestamp updateTime;
 
    public SellerInfoEntity() {
    }
 
    public SellerInfoEntity(String id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
}

使用注解前

{
    "id":"1",
    "username":"user1",
    "password":"123456",
    "createTime":null,
    "updateTime":null
}

使用注解后,不会从JSON读取或写入JSON属性(createTime、updateTime)

{
    "id":"1",
    "username":"user1",
    "password":"123456"
}

@JsonIgnoreProperties

  与 @JsonIgnore 类似,都是告诉 Jackson 该忽略哪些属性,不同之处是 @JsonIgnoreProperties 是类级别的,放置在类声明上方,达到在序列化时忽略一个或多个字段的效果。

@Data
@JsonIgnoreProperties(value = {"createTime","updateTime"})
public class SellerInfoEntity {
 
    private String id;
    private String username;
    private String password;
    private String openid;
    private Timestamp createTime;
    private Timestamp updateTime;
 
    public SellerInfoEntity() {
    }
 
    public SellerInfoEntity(String id, String username, String password) {
        this.id = id;
        this.username = username;
        this.password = password;
    }
}

在此示例中,属性createTime、updateTime都将被忽略,因为它们的名称在类声明上方的 @JsonIgnoreProperties 注解声明内列出。

在目标对象的类级别上添加注解:@JsonIgnoreProperties(ignoreUnknown = true),用于忽略字段不匹配情况。

@JsonInclude

使用@JsonInclude注解告诉Jackson仅在某些情况下包括属性。 例如,仅当属性为非null,非空或具有非默认值时,才应包括该属性。

@JsonInclude(Include.NON_NULL)
public class MyBean {
    public int id;
    public String name;
}

在MyBean中使用了Include.NON_NULL则代表该实体对象序列化时不会包含空值。

3.4 常规注解

@JsonProperty

  类似于sql里字段的别名,可以指定某个属性和json映射的名称。当实体对象中没有标准的getter/setter方法时,我们可以使用该注解进行指定属性名称,方便进行序列化/反序列化。例如我们有个json字符串为{"user_name":"aaa"},而java中命名要遵循驼峰规则,则为userName,这时通过 @JsonProperty 注解来指定两者的映射规则即可。

public class SomeEntity {
    @JsonProperty("user_name")
    private String userName;
      // ...
}

@JsonFormat

  此注解用于属性上,针对日期字段可以通过使用@JsonFormat注解直接转化为指定的格式,例如 @JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。主要有下面几个常用的属性

属性说明
shap表示序列化后的一种类型
pattern表示日期的格式
timezone若未标明时区,则默认为 GMT 时区,中国需要GMT+8
locale根据位置序列化的一种格式
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy年MM月dd日 HH:mm:ss", timezone = "GMT+8")
private Date date;

@JsonFormat(shape = JsonFormat.Shape.NUMBER)
private Date date2;

@JsonFormat(locale = "zh_CN")
private Date date3;

跟 JsonSerializer 类似,如下所示:

@JsonSerialize(using = CustomDateSerializer.class) 
private Date dateOfBirth; 

class CustomDateSerializer extends JsonSerializer{
   private static final long serialVersionUID = 1L; 
   private static SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
   @Override 
   public void serialize(Date value, 
      JsonGenerator generator, SerializerProvider arg2) throws IOException { 
      generator.writeString(formatter.format(value)); 
   } 
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独泪了无痕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值