Jackson注解入门示例

本文详细介绍了Jackson库中各种注解的功能与应用场景,包括解决JSON字段与Java Bean字段不匹配的问题,以及如何处理多态、循环引用等复杂情况。

jackson目的是什么呢? 它是解决json和bean之间对应关系,json就是字符和java的bean如何进行关联,json字符和bean之间会有哪些问题呢?

1、预先思考

  • 最理想情况下,就json和bean是一一对应,层次结构相同,成员变量和json的key对应字符串相同,这样json也是最好处理。

1.1、json和bean会有什么问题呢?

  1. 当一个系统与多个系统进行交互的时候采用json格式,不同系统生成json格式层次和json中的key可能不同
  2. 比如说A系统用户名字段是userName , B系统中用户名字段user_name, 我们系统定义用户名字段userN,这个时候怎么做
    1. 方案一:对方系统转换成我们系统字段名传给我们
    2. 方案二:对方已经成熟系统不愿意改,我们系统写一个适配器接收两个系统原始进行转换成标准的(当差异很大时候,这个方式比较合理),如果只是字段名微调就重新定义一个适配器有那个啥?
    3. 方案三:jackson可以解决这种适配情况(json字段与bean字段一对多的关系)
  3. json对象的字段不一定,不同场景传递字段不一样且数量不定,比如说订单,比如对接多个快递公司,每个快递公司填信息不一样,传到我们系统时候,有时候这个字段存在,有时它不存在,此时我们怎么定义bean呢?
    1. 方案一:把所有可能字段全部定义
    2. 方案二:把可变对象定义成一个字段JsonObject对象之类,其实它本质也就一个map
    3. 方案三:jackson注解简单解决这个问题,本质上也是map
  4. json 和枚举关系怎么对应,到底是对应枚举那个属性和枚举本身的name?这个jackson也可以配置
  5. json 和bean多态怎么对应呢?场景是这样的,就拿订单来说,订单主信息是一样,而明细可以不一样,比如下预售订单和现货订单就不一样?那此时你在想我需要对预售订单和现货订单分别提供接口,如果只提供一个接口怎么实现呢?这个时候需要在解析json时候如何对应不同明细子类呢?jackson也是有这种特性
  6. 有时候我需要忽略null转成json字符串中,或者说觉得某个字段不需要转成json字符,如何灵活配置忽略字段呢?
  7. 格式转换,比如说数据库查询出来是10000,我们希望转给前端是$10,000, 或者前端传给我们是$10,000,我们转换成10000,jackson可以定义转换逻辑
  8. 如果bean出现循环依赖,转成json应该是什么样?怎么解决?
  • 带这个问题去了解jackson

2、具体jackson注解

2.1、@JsonAnySetter

  • 将Map的属性变成bean的属性,且动态变化的,变成bean属性时,key就是属性名称, value就是属性值。

  • public class ExtendableBean {
        public String name;
        private Map<String, String> properties;
    
        @JsonAnyGetter
        public Map<String, String> getProperties() {
            return properties;
        }
    }
    
    
    @Test
    public void whenSerializingUsingJsonAnyGetter_thenCorrect()
      throws JsonProcessingException {
     
        ExtendableBean bean = new ExtendableBean("My bean");
        bean.add("attr1", "val1");
        bean.add("attr2", "val2");
    
        String result = new ObjectMapper().writeValueAsString(bean);
     
        assertThat(result, containsString("attr1"));
        assertThat(result, containsString("val1"));
    }
    
  • 输出结果

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

2.2、@JsonGetter /@JsonSetter

  • 当方法和属性不同时候就可以利用@JsonGetter/@JsonSetter指定某一个属性

  • public class MyBean {
        public int id;
        private String name;
    
        @JsonGetter("name")
        public String getTheName() {
            return name;
        }
    }
    
    @Test
    public void whenSerializingUsingJsonGetter_thenCorrect()
      throws JsonProcessingException {
     
        MyBean bean = new MyBean(1, "My bean");
    
        String result = new ObjectMapper().writeValueAsString(bean);
     
        assertThat(result, containsString("My bean"));
        assertThat(result, containsString("1"));
    }
    

2.3、@JsonPropertyOrder

  • 指定序列化字段顺序,这个场景用的不是很多,@JsonPropertyOrder(alphabetic = true) 表示按照26字母顺序排序

  • @JsonPropertyOrder({ "name", "id" })
    public class MyBean {
        public int id;
        public String name;
    }
    
    @Test
    public void whenSerializingUsingJsonPropertyOrder_thenCorrect()
      throws JsonProcessingException {
     
        MyBean bean = new MyBean(1, "My bean");
    
        String result = new ObjectMapper().writeValueAsString(bean);
        assertThat(result, containsString("My bean"));
        assertThat(result, containsString("1"));
    }
    
  • 输出结果

    • {
          "name":"My bean",
          "id":1
      }
      

2.4、@JsonRawValue

  • 过滤某个字段不要jackson进行处理,只适合将bean转换成json字符串,不能用json字符串转成bean

  • public class RawBean {
        public String name;
    
        @JsonRawValue
        public String json;
    }
    
    @Test
    public void whenSerializingUsingJsonRawValue_thenCorrect()
      throws JsonProcessingException {
     
        RawBean bean = new RawBean("My bean", "{\"attr\":false}");
    
        String result = new ObjectMapper().writeValueAsString(bean);
        assertThat(result, containsString("My bean"));
        assertThat(result, containsString("{\"attr\":false}"));
    }
    
  • 输出结果

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

2.5、@JsonValue

  • 一般用于枚举到达使用哪个值进行序列化,某个实体中只序列化某个方法和成员变量

  • public enum TypeEnumWithValue {
        TYPE1(1, "Type A"), TYPE2(2, "Type 2");
    
        private Integer id;
        private String name;
    
        // standard constructors
    
        @JsonValue
        public String getName() {
            return name;
        }
    }
    
    @Test
    public void whenSerializingUsingJsonValue_thenCorrect()
      throws JsonParseException, IOException {
     
        String enumAsString = new ObjectMapper()
          .writeValueAsString(TypeEnumWithValue.TYPE1);
    
        assertThat(enumAsString, is(""Type A""));
    }
    

2.6、@JsonRootName

  • 需要开启WRAP_ROOT_VALUE开关 ,实例化成json时候套个壳,多加一层

  • @JsonRootName(value = "user")public class UserWithRoot {    public int id;    public String name;}@Testpublic void whenSerializingUsingJsonRootName_thenCorrect()  throws JsonProcessingException {     UserWithRoot user = new User(1, "John");    ObjectMapper mapper = new ObjectMapper();    mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);    String result = mapper.writeValueAsString(user);    assertThat(result, containsString("John"));    assertThat(result, containsString("user"));}
    
  • 输出结果

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

2.7、@JsonSerialize 和@JsonDeserialize

  • 自定义序列化和反序列类

  • public class EventWithSerializer {    public String name;    @JsonSerialize(using = CustomDateSerializer.class)    public Date eventDate;}public class CustomDateSerializer extends StdSerializer<Date> {    private static SimpleDateFormat formatter       = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");    public CustomDateSerializer() {         this(null);     }     public CustomDateSerializer(Class<Date> t) {        super(t);     }    @Override    public void serialize(      Date value, JsonGenerator gen, SerializerProvider arg2)       throws IOException, JsonProcessingException {        gen.writeString(formatter.format(value));    }}@Testpublic void whenSerializingUsingJsonSerialize_thenCorrect()  throws JsonProcessingException, ParseException {     SimpleDateFormat df      = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");    String toParse = "20-12-2014 02:30:00";    Date date = df.parse(toParse);    EventWithSerializer event = new EventWithSerializer("party", date);    String result = new ObjectMapper().writeValueAsString(event);    assertThat(result, containsString(toParse));}
    

2.8、@JsonCreator

  • 构造器方法

  • 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;    }}@Testpublic void whenDeserializingUsingJsonCreator_thenCorrect()  throws IOException {     String json = "{\"id\":1,\"theName\":\"My bean\"}";    BeanWithCreator bean = new ObjectMapper()      .readerFor(BeanWithCreator.class)      .readValue(json);    assertEquals("My bean", bean.name);}
    
  • 输出

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

2.9、@JacksonInject

  • json字符串没有对应的字段,就需要预先通过注射一个值

  • public class BeanWithInject {    @JacksonInject    public int id;        public String name;}@Testpublic void whenDeserializingUsingJsonInject_thenCorrect()  throws IOException {     String json = "{\"name\":\"My bean\"}";        InjectableValues inject = new InjectableValues.Std()      .addValue(int.class, 1);    BeanWithInject bean = new ObjectMapper().reader(inject)      .forType(BeanWithInject.class)      .readValue(json);        assertEquals("My bean", bean.name);    assertEquals(1, bean.id);}
    

2.10、@JsonAlias

  • json多个名称对应一个bean上字段

  • public class AliasBean {    @JsonAlias({ "fName", "f_name" })    private String firstName;       private String lastName;}@Testpublic void whenDeserializingUsingJsonAlias_thenCorrect() throws IOException {    String json = "{\"fName\": \"John\", \"lastName\": \"Green\"}";    AliasBean aliasBean = new ObjectMapper().readerFor(AliasBean.class).readValue(json);    assertEquals("John", aliasBean.getFirstName());}
    

2.11、@JsonIgnoreProperties

  • 类级别注解, 忽略某一些字段

  • @JsonIgnoreProperties({ "id" })public class BeanWithIgnore {    public int id;    public String name;}@Testpublic void whenSerializingUsingJsonIgnoreProperties_thenCorrect()  throws JsonProcessingException {     BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");    String result = new ObjectMapper()      .writeValueAsString(bean);        assertThat(result, containsString("My bean"));    assertThat(result, not(containsString("id")));}
    

2.12、@JsonIgnore

  • 成员变量的,忽略单个字段

  • public class BeanWithIgnore {    @JsonIgnore    public int id;    public String name;}
    
  • @Testpublic void whenSerializingUsingJsonIgnore_thenCorrect()  throws JsonProcessingException {     BeanWithIgnore bean = new BeanWithIgnore(1, "My bean");    String result = new ObjectMapper()      .writeValueAsString(bean);        assertThat(result, containsString("My bean"));    assertThat(result, not(containsString("id")));}
    

2.13、@JsonIgoreType

  • 忽略某类型的字段

  • public class User {    public int id;    public Name name;    @JsonIgnoreType    public static class Name {        public String firstName;        public String lastName;    }}@Testpublic void whenSerializingUsingJsonIgnoreType_thenCorrect()  throws JsonProcessingException, ParseException {     User.Name name = new User.Name("John", "Doe");    User user = new User(1, name);    String result = new ObjectMapper()      .writeValueAsString(user);    assertThat(result, containsString("1"));    assertThat(result, not(containsString("name")));    assertThat(result, not(containsString("John")));}
    

2.14、@JsonInclude

  • 哪些字段包括在内进行序列化

  • @JsonInclude(Include.NON_NULL)public class MyBean {    public int id;    public String name;}public void whenSerializingUsingJsonInclude_thenCorrect()  throws JsonProcessingException {     MyBean bean = new MyBean(1, null);    String result = new ObjectMapper()      .writeValueAsString(bean);        assertThat(result, containsString("1"));    assertThat(result, not(containsString("name")));}
    

2.15、@JsonAutoDetect

  • 自动检测,哪些限制修饰符属性可以json序列化

  • @JsonAutoDetect(fieldVisibility = Visibility.ANY)public class PrivateBean {    private int id;    private String name;}@Testpublic void whenSerializingUsingJsonAutoDetect_thenCorrect()  throws JsonProcessingException {     PrivateBean bean = new PrivateBean(1, "My bean");    String result = new ObjectMapper()      .writeValueAsString(bean);        assertThat(result, containsString("1"));    assertThat(result, containsString("My bean"));}
    

2.16、@JsonTypeInfo

  • 序列化的详细信息

  • public class Zoo {    public Animal animal;    @JsonTypeInfo(      use = JsonTypeInfo.Id.NAME,       include = 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;    }    @JsonTypeName("dog")    public static class Dog extends Animal {        public double barkVolume;    }    @JsonTypeName("cat")    public static class Cat extends Animal {        boolean likesCream;        public int lives;    }}@Testpublic void whenSerializingPolymorphic_thenCorrect()  throws JsonProcessingException {    Zoo.Dog dog = new Zoo.Dog("lacy");    Zoo zoo = new Zoo(dog);    String result = new ObjectMapper()      .writeValueAsString(zoo);    assertThat(result, containsString("type"));    assertThat(result, containsString("dog"));}
    
  • 输出

    • {    "animal": {        "type": "dog",        "name": "lacy",        "barkVolume": 0    }}
      
  • 反序列化

    • @Testpublic void whenDeserializingPolymorphic_thenCorrect()throws IOException {    String json = "{\"animal\":{\"name\":\"lacy\",\"type\":\"cat\"}}";    Zoo zoo = new ObjectMapper()      .readerFor(Zoo.class)      .readValue(json);    assertEquals("lacy", zoo.animal.name);    assertEquals(Zoo.Cat.class, zoo.animal.getClass());}
      

2.17、@JsonSubTypes

  • 表示子类注解(对应关系)

2.18、@JsonTypeName

  • 表示对应值

2.19、@JsonFormat

  • json格式化,一般是日期和字符串之间转换

  • public class EventWithFormat {    public String name;    @JsonFormat(      shape = JsonFormat.Shape.STRING,      pattern = "dd-MM-yyyy hh:mm:ss")    public Date eventDate;}@Testpublic void whenSerializingUsingJsonFormat_thenCorrect()  throws JsonProcessingException, ParseException {    SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss");    df.setTimeZone(TimeZone.getTimeZone("UTC"));    String toParse = "20-12-2014 02:30:00";    Date date = df.parse(toParse);    EventWithFormat event = new EventWithFormat("party", date);        String result = new ObjectMapper().writeValueAsString(event);        assertThat(result, containsString(toParse));}
    

2.20、@JsonUnwrapped

  • 去掉属性外壳,有点类似java8 map flat 操作

  • public class UnwrappedUser {    public int id;    @JsonUnwrapped    public Name name;    public static class Name {        public String firstName;        public String lastName;    }}@Testpublic void whenSerializingUsingJsonUnwrapped_thenCorrect()  throws JsonProcessingException, ParseException {    UnwrappedUser.Name name = new UnwrappedUser.Name("John", "Doe");    UnwrappedUser user = new UnwrappedUser(1, name);    String result = new ObjectMapper().writeValueAsString(user);        assertThat(result, containsString("John"));    assertThat(result, not(containsString("name")));}
    
  • 输出

    • {    "id":1,    "firstName":"John",    "lastName":"Doe"}
      

2.21、@JsonView

  • json视图,定义一些标签,每次只序列化特定视图

  • public class Views {    public static class Public {}    public static class Internal extends Public {}}public class Item {    @JsonView(Views.Public.class)    public int id;    @JsonView(Views.Public.class)    public String itemName;    @JsonView(Views.Internal.class)    public String ownerName;}@Testpublic void whenSerializingUsingJsonView_thenCorrect()  throws JsonProcessingException {    Item item = new Item(2, "book", "John");    String result = new ObjectMapper()      .writerWithView(Views.Public.class)      .writeValueAsString(item);    assertThat(result, containsString("book"));    assertThat(result, containsString("2"));    assertThat(result, not(containsString("John")));}
    

2.22、@JsonManagedReference

  • @JsonBackReference

  • 解决循环引用问题

  • public class ItemWithRef {
        public int id;
        public String itemName;
    
        @JsonManagedReference
        public UserWithRef owner;
    }
    
    public class UserWithRef {
        public int id;
        public String name;
    
        @JsonBackReference
        public List<ItemWithRef> userItems;
    }
    
    @Test
    public void whenSerializingUsingJacksonReferenceAnnotation_thenCorrect()
      throws JsonProcessingException {
        UserWithRef user = new UserWithRef(1, "John");
        ItemWithRef item = new ItemWithRef(2, "book", user);
        user.addItem(item);
    
        String result = new ObjectMapper().writeValueAsString(item);
    
        assertThat(result, containsString("book"));
        assertThat(result, containsString("John"));
        assertThat(result, not(containsString("userItems")));
    }
    

2.23、@JsonIdentityInfo

  • 也是解决循环依赖问题,它会标记循环起点

  • @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class,
      property = "id")
    public class ItemWithIdentity {
        public int id;
        public String itemName;
        public UserWithIdentity owner;
    }
    
    
    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class,
      property = "id")
    public class UserWithIdentity {
        public int id;
        public String name;
        public List<ItemWithIdentity> userItems;
    }
    
    @Test
    public void whenSerializingUsingJsonIdentityInfo_thenCorrect()
      throws JsonProcessingException {
        UserWithIdentity user = new UserWithIdentity(1, "John");
        ItemWithIdentity item = new ItemWithIdentity(2, "book", user);
        user.addItem(item);
    
        String result = new ObjectMapper().writeValueAsString(item);
    
        assertThat(result, containsString("book"));
        assertThat(result, containsString("John"));
        assertThat(result, containsString("userItems"));
    }
    
  • 输出

    • {
          "id": 2,
          "itemName": "book",
          "owner": {
              "id": 1,
              "name": "John",
              "userItems": [
                  2
              ]
          }
      }
      

2.24、@JsonFilter

  • json过滤器,过滤某个字段

  • @JsonFilter("myFilter")
    public class BeanWithFilter {
        public int id;
        public String name;
    }
    
    @Test
    public void whenSerializingUsingJsonFilter_thenCorrect()
      throws JsonProcessingException {
        BeanWithFilter bean = new BeanWithFilter(1, "My bean");
    
        FilterProvider filters 
          = new SimpleFilterProvider().addFilter(
            "myFilter", 
            SimpleBeanPropertyFilter.filterOutAllExcept("name"));
    
        String result = new ObjectMapper()
          .writer(filters)
          .writeValueAsString(bean);
    
        assertThat(result, containsString("My bean"));
        assertThat(result, not(containsString("id")));
    }
    

引用

例子来自于: [Jackson Annotation Examples](

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值