读 + 写 注解
@JsonIgnore
在将Java对象序列化为json时,有些属性需要过滤掉,不显示在json中,可以使用@JsonIgnore
忽略单个字段。
public class PersonIgnore {
@JsonIgnore
public long personId = 0;
public String name = null;
}
@JsonIgnoreProperties
作用于类,表示被注解该类型的属性将不会被序列化和反序列化
@Test
public void jsonFilter() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setName("myName");
Sub1 sub1 = new Sub1();
sub1.setId(1);
sub1.setName("sub1");
Sub2 sub2 = new Sub2();
sub2.setId(2);
sub2.setAge(22);
testPOJO.setMyIn(sub1);
testPOJO.setSub1(sub1);
testPOJO.setSub2(sub2);
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
System.out.println(jsonStr);
}
public static class TestPOJO{
private Sub1 sub1;
private Sub2 sub2;
private MyIn myIn;
private String name;
//getters、setters省略
}
public static class MyIn{
private int id;
//getters、setters省略
}
@JsonIgnoreType
public static class Sub1 extends MyIn{
private String name;
//getters、setters省略
}
@JsonIgnoreType
public static class Sub2 extends MyIn{
private int age;
//getters、setters省略
}
上面例子中我们在类Sub1和Sub2上都加上了@JsonIgnoreType,那么需要序列化和反序列时POJO中所有Sub1和Sub2类型的属性都将会被忽略,上面测试结果为{“myIn”:{“id”:1,“name”:“sub1”},“name”:“myName”},只输出了name和myIn属性。需要注意的是@JsonIgnoreType是可以继承的,即如果在基类上添加了该注解,那么子类也相当于加了该注解。在上例中,如果只在基类MyIn上添加@JsonIgnoreType那么序列化TestPOJO时将会过滤掉MyIn、Sub1、Sub2。输出结果为{“name”:“myName”}
@JsonAutoDetect
开启/禁止自动检测
fieldVisibility:字段的可见级别
ANY:任何级别的字段都可以自动识别
NONE:所有字段都不可以自动识别
NON_PRIVATE:非private修饰的字段可以自动识别
PROTECTED_AND_PUBLIC:被protected和public修饰的字段可以被自动识别
PUBLIC_ONLY:只有被public修饰的字段才可以被自动识别
DEFAULT:同PUBLIC_ONLY
jackson默认的字段属性发现规则如下:
所有被public修饰的字段->所有被public修饰的getter->所有被public修饰的setter
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY )
public class PersonAutoDetect {
private long personId = 123;
public String name = null;
}
这个类我们没有提供对应的get,set方法,如果按照默认的属性发现规则我们将无法序列化和反序列化personId字段(如果没有get,set方法,只有被public修饰的属性才会被发现),你可以通过修改@JsonAutoDetect的fieldVisibility来调整自动发现级别,为了使name被自动发现,我们需要将级别调整为ANY
@JsonProperty
作用在字段或方法上,用来对属性的序列化/反序列化,可以用来避免遗漏属性,同时提供对属性名称重命名,比如在很多场景下Java对象的属性是按照规范的驼峰书写,但是实际展示的却是类似C-style或C++/Microsolft style
@Test
public void jsonPropertyTest() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.wahaha(111);
testPOJO.setFirstName("myName");
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
Assert.assertEquals("{\"id\":111,\"first_name\":\"myName\"}",jsonStr);
String jsonStr2 = "{\"id\":111,\"first_name\":\"myName\"}";
TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2, TestPOJO.class);
Assert.assertEquals(111, testPOJO2.wahaha());
Assert.assertEquals("myName", testPOJO2.getFirstName());
}
public static class TestPOJO{
@JsonProperty//注意这里必须得有该注解,因为没有提供对应的getId和setId函数,而是其他的getter和setter,防止遗漏该属性
private int id;
@JsonProperty("first_name")
private String firstName;
public int wahaha() {
return id;
}
public void wahaha(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
@JsonUnwrapped
作用在属性字段或方法上,用来将子JSON对象的属性添加到封闭的JSON对象,说起来比较难懂,看个例子就很清楚了,不多解释
@Test
public void jsonUnwrapped() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setId(111);
TestName testName = new TestName();
testName.setFirstName("张");
testName.setSecondName("三");
testPOJO.setName(testName);
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
//如果没有@JsonUnwrapped,序列化后将为{"id":111,"name":{"firstName":"张","secondName":"三"}}
//因为在name属性上加了@JsonUnwrapped,所以name的子属性firstName和secondName将不会包含在name中。
Assert.assertEquals("{\"id\":111,\"firstName\":\"张\",\"secondName\":\"三\"}",jsonStr);
String jsonStr2 = "{\"id\":111,\"firstName\":\"张\",\"secondName\":\"三\"}";
TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
Assert.assertEquals(111,testPOJO2.getId());
Assert.assertEquals("张",testPOJO2.getName().getFirstName());
Assert.assertEquals("三",testPOJO2.getName().getSecondName());
}
public static class TestPOJO{
private int id;
@JsonUnwrapped
private TestName name;
//getters、setters省略
} public static class TestName{
private String firstName;
private String secondName;
//getters、setters省略
}
在2.0+版本中@JsonUnwrapped添加了prefix和suffix属性,用来对字段添加前后缀,这在有关属性分组上比较有用,在上面的测试用例中,如果我们将TestPOJO的name属性上的@JsonUnwrapped添加前后缀配置,即
@JsonUnwrapped(prefix = "name_",suffix = "_test")
那么TestPOJO序列化后将为{“id”:111,“name_firstName_test”:“张”,“name_secondName_test”:“三”},反序列化时也要加上前后缀才会被解析为POJO
@JsonRootName
使用在类上,标注为该类在转换为json string的时候,需要新增一个根节点rootNode
@JsonRootName("myPojo")
public static class TestPOJO{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
该类在序列化成json后类似如下:{“myPojo”:{“name”:“aaaa”}}
读 注解
@JsonAnySetter
作用于方法,在反序列化时用来处理遇到未知的属性的时候调用,@JsonAnySetter
和map属性配合使用用来保存未知的属性
@Test
public void jsonAnySetter() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"name\":\"myName\",\"code\":\"12345\",\"age\":12}";
TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("myName",testPOJO.getName());
Assert.assertEquals("12345",testPOJO.getOther().get("code"));
Assert.assertEquals(12,testPOJO.getOther().get("age"));
}
public static class TestPOJO{
private String name;
private Map other = new HashMap();
@JsonAnySetter
public void set(String name,Object value) {
other.put(name,value);
}
//getters、setters省略
}
@JsonCreator
作用于方法,通常用来标注构造方法或静态工厂方法上,使用该方法来构建实例,默认的是使用无参的构造方法,通常是和@JsonProperty
或@JacksonInject
配合使用
@Test
public void jsonCreator() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"full_name\":\"myName\",\"age\":12}";
TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("myName",testPOJO.getName());
Assert.assertEquals(12, testPOJO.getAge());
}
public static class TestPOJO{
private String name;
private int age;
@JsonCreator
public TestPOJO(@JsonProperty("full_name") String name,@JsonProperty("age") int age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
上面示例中是在构造方法上标注了@JsonCreator
,同样你也可以标注在静态工厂方法上,比如:
@Test
public void jsonCreator() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"name\":\"myName\",\"birthday\":1416299461556}";
TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("myName",testPOJO.getName());
System.out.println(testPOJO.getBirthday());
}
public static class TestPOJO{
private String name;
private Date birthday;
private TestPOJO(String name,Date birthday){
this.name = name;
this.birthday = birthday;
}
@JsonCreator
public static TestPOJO getInstance(@JsonProperty("name") String name,@JsonProperty("birthday") long timestamp){
Date date = new Date(timestamp);
return new TestPOJO(name,date);
}
public String getName() {
return name;
}
public Date getBirthday() {
return birthday;
}
}
这个实例中,TestPOJO的构造方法是私有的,外面无法new出来该对象,只能通过工厂方法getInstance来构造实例,此时@JsonCreator
就标注在工厂方法上。
除了这2种方式外,还有一种构造方式成为授权式构造器,也是我们平常比较常用到的,这个构造器只有一个参数,且不能使用@JsonProperty
@Test
public void jsonCreator() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"full_name\":\"myName\",\"age\":12}";
TestPOJO testPOJO = objectMapper.readValue(jsonStr,TestPOJO.class);
Assert.assertEquals("myName",testPOJO.getName());
Assert.assertEquals(12,testPOJO.getAge());
}
public static class TestPOJO{
private String name;
private int age;
@JsonCreator
public TestPOJO(Map map){
this.name = (String)map.get("full_name");
this.age = (Integer)map.get("age");
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
@JacksonInject
作用于属性、方法、构造参数上,被用来反序列化时标记已经被注入的属性。
@Test
public void jacksonInject() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = "{\"age\":12}";
InjectableValues inject = new InjectableValues.Std().addValue("name","myName");
TestPOJO testPOJO = objectMapper.reader(TestPOJO.class).with(inject).readValue(jsonStr);
Assert.assertEquals("myName", testPOJO.getName());
Assert.assertEquals(12,testPOJO.getAge());
}
public static class TestPOJO{
@JacksonInject("name")
private String name;
private int age;
//getters、setters省略
}
@JsonDeserialize
作用于方法和字段上,通过using(JsonDeserializer)
来指定反序列化的实现,通常我们在需要自定义反序列化时会用到,比如下面的例子中的日期转换
@Test
public void jsonSerializeAndDeSerialize() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setName("myName");
testPOJO.setBirthday(new Date());
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
System.out.println(jsonStr);
String jsonStr2 = "{\"name\":\"myName\",\"birthday\":\"2014-11-11 19:01:58\"}";
TestPOJO testPOJO2 = objectMapper.readValue(jsonStr2,TestPOJO.class);
System.out.println(testPOJO2.toString());
}
public static class TestPOJO{
private String name;
@JsonDeserialize(using = MyDateDeserializer.class)
private Date birthday;
//getters、setters省略
@Override
public String toString() {
return "TestPOJO{" +
"name='" + name + '\'' +
", birthday=" + birthday +
'}';
}
}
private static class MyDateDeserializer extends JsonDeserializer<Date>{
@Override
public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String value = jp.getValueAsString();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
return dateFormat.parse(value);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
写 注解
@JsonInclude
是用再实体类的方法类的头上 作用是实体类的参数查询到的为null的不显示
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PersonInclude {
public long personId = 0;
public String name = null;
}
@JsonAnyGetter
跟@JsonAnyGetter
相反
public class PersonAnyGetter {
private Map<String, Object> properties = new HashMap<>();
@JsonAnyGetter
public Map<String, Object> properties() {
return properties;
}
}
@JsonPropertyOrder
作用在类上,被用来指明当序列化时需要对属性做排序,它有2个属性
一个是alphabetic:布尔类型,表示是否采用字母拼音顺序排序,默认是为false,即不排序
@Test
public void jsonPropertyOrder() throws Exception {
TestPOJO testPOJO = new TestPOJO();
testPOJO.setA("1");
testPOJO.setB("2");
testPOJO.setC("3");
testPOJO.setD("4");
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(testPOJO);
System.out.println(jsonStr);
Assert.assertEquals("{\"c\":\"3\",\"b\":\"2\",\"a\":\"1\",\"d\":\"4\"}",jsonStr);
}
@JsonPropertyOrder(alphabetic = true,value = {"c","b"})
public static class TestPOJO{
private String a;
private String c;
private String d;
private String b;
//getters、setters省略
}
上面例子可以看到value指定了c和b属性优先排序,所以序列化后为{“c”:“3”,“b”:“2”,“a”:“1”,“d”:“4”}
@JsonValue
标注方法,用以替代缺省的方法,由该方法来完成json的字符输出
public class PersonValue {
public long personId = 0;
public String name = null;
@JsonValue
public String toJson(){
return this.personId + "," + this.name;
}
}
输出"0,null"
@JsonFormat
格式化
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
public Timestamp getCreate_time() {
return create_time;
}
@JsonSerialize
跟@JsonDeserialize
相反
@JsonView
@JsonView注解用来过滤序列化对象的字段属性,简单来说就是定义一个标签,根据controller的JsonView属性,将实体类中不同标签的属性进行分类显示。
例:
首先定义一个view类,有两个接口Summary 和SummaryWithDetail :
public class View {
public interface Summary {}
public interface SummaryWithDetail extends Summary{}
}
然后定义一个实体类User,选择属性分别加上注解@JsonView(View.Summary.class) 或@JsonView(View.SummaryWithDetail .class)
public class User {
@JsonView(View.Summary.class)
private Long id;
@JsonView(View.Summary.class)
private String firstname;
@JsonView(View.Summary.class)
private String lastname;
@JsonView(View.SummaryWithDetail .class)
private String email;
@JsonView(View.SummaryWithDetail .class)
private String address;
private String postalCode;
private String city;
private String country;
...
}
定义Controller类,加上@JsonView注解:
@RestController
public class UserRestController{
@Autowired
private UserService userService;
@RequestMapping("/user")
@JsonView(View.Summary.class)
public List<User> getUsers(){
return userService.listUsers();
}
@RequestMapping("/userWithDetail")
@JsonView(View.SummaryWithDetail.class)
public List<User> getUsersWithDetail(){
return userService.listUsers();
}
}
访问/user时,使用的注解是@JsonView(View.Summary.class),所以仅显示注解为@JsonView(View.Summary.class)的属性,结果为:
[
{ “id” : 1, “firstname” : “Brian”, “lastname” : “Clozel” },
{ “id” : 2, “firstname” : “Stéphane”, “lastname” : “Nicoll” },
{ “id” : 3, “firstname” : “Rossen”, “lastname” : “Stoyanchev” }
]
访问/userWithDetail时,使用的注解是@JsonView(View.SummaryWithDetail.class),结果显示注解为@JsonView(View.SummaryWithDetail.class)的属性,同时由于SummaryWithDetail继承于Summary,结果也包含注解为@JsonView(View.Summary.class)的属性,结果为:
[
{
“id” : 1,
“firstname” : “Brian”,
“lastname” : “Clozel”,
“email”: “brian@163.com”,
“address”: “beijing China”
},
{
“id” : 2,
“firstname” : “Stéphane”,
“lastname” : “Nicoll”,
“email”: “nicoll@163.com”,
“address”: “beijing China”
},
{
“id” : 3,
“firstname” : “Rossen”,
“lastname” : “Stoyanchev” ,
“email”: “stoyanchev@163.com”,
“address”: “beijing China”
}
]