jackson的注解

一、问题

1.1 真实案例

构造一个java对象,这个class在java内存中就是一个你想处理的对象。当然这个对象也需要存在redis,等待下次定时事件或者其他消费事件处理。另外这个对象也需要在网络上传输。所以你需要一个构造class的成员。

网络(JSON)       ~         内存(class 实例)     ~        redis存储(String)
                <- 序列化                       序列化->
                反序列化->                      反序列化<-

这个class对象在网络中就是一串json格式串。json格式串处理了网络流中需要知道消息的边界信息。而在redis存储中需要是把任何type的对象转化成string。所以需要进行一系列的序列化和反序列化转换。

1.2 传统做法

构建一个类testObject。考虑redis String对象和class对象的序列化/反序列化过程。需要这种类型的构造函数:

  • 反序列化:testObject(String or Map<String, String>){}
  • 序列化:Map<String, String>toRedisMap()

和网络json对象的序列化和反序列化过程:

public class  testObject
{
       private String m1;
       private List<String> m2;
       private XXX m3;
       
       // from network JSON
       testObject (){
       }
       
       //from redis String
       testObject(String or Map<String, String>) {
       }
       
       //copy from other class
       testObject(class or Map<String Key, Object Value>){
       }

       //for map type Redis oper api
       public Map<String, String> toRedisMap () {
     
       }
    
       //for get this class instance and manipulate
       public Map<String, Object> toClientMap() {
       }
    
       //for print
       @Override
       public String toString() {
       }
    
       //for save key
       @Override
       public int hashCode() {
       }
    
}

1.3 扩展问题

序列化和反序列化的过程:还需要实现一些合规检查。检查是否允许非空value,是否可解析(比如说数字是否可解析),大小写,,大小写,有些字段只存在于某一阶段(比如说推送信息的一些控制字段,不会push给客户端),更换key的名字等。这些完整性实现需要引入必要的代码,而且这些跟业务逻辑无关的代码引入也会导致后期维护的困难。

二、解决问题

Jackson用注解的形式解决了以上问题,让代码更简洁,也,只需要安装Jackson的Annotation注解使用方式写法即可。Jackson帮助完成了类的序列化/反序列化以及必要的检查。

2.1 JsonProperty和JsonCreator

JsonCreator和JsonProperites搭配使用

2.1.1 JsonProperty:设置序列化/反序列化的名字映射关系,映射class的成员和JSON的key字段

还是上面那个例子:

public class testObject {
        @JsonProperty("firstName")
         public String _first_name
}

这里的class成员_first_name就和JSON的firstName的key映射上了。这里需要注意的是,这是比较一般都这样写。在序列化/反序列化都可以对应上。而已经过时的JsonGetter或者JsonSettor只会在序列化或者反序列化的单边转化中有效。

2.1.2 JsonCreator

注解在构造函数或者工厂类的实例化对象函数上。JsonCreator最常用还是和 JsonProperty使用,当然它也可以跟JsonValue搭配或者和JacksonInject搭配。

和JsonProperty搭配的写法如下:

@JsonCreator
public testObject(@JsonProperty("firstName") String _first_name) {
    this._first_name = first_name;
}

或者写个空的,然后JsonProperty注解在field上也可以。

public class testObject {
        @JsonProperty("firstName")
         public String _first_name;
         
         @JsonCreator
         public testObject() {}
}

2.2 JsonGetter和JsonSetter(过时的写法)

JsonSetter和JsonGetter搭配使用

@JsonGetterand@JsonSetterare 是过时的,现在一般用@JsonProperty写法。

三、原理

我们翻开了jaskson-annotations-2.9.9-sources.jar/com/faster.xml/jackson/annotation目录,查看了每个annotation的实现。

3.1 JsonProperty.java

@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonProperty
{
}

这里标识了元注解 JacksonAnnotaion的@Target, @Retention, @JacksonAnnotation的实现。

  • Target表面了这个annotation的可应用场合。包括TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE, MODULE。这里表面可用于成员变量,方法和参数。ElementType.ANNOTATION_TYPE又称元注解 (meta-annotation)。元注解可以和其他元注解组成更强大的注解。
  • Retention标识了是哪个阶段解析注解。

同时 这里其实还有看到几个可以设置的选项:

图1 JsonProperty的一些成员
  • required:是否可忽略没有这个字段
  • access:可读写/只读/只写
  • defaultValue:默认值

3.2 JsonCreator.java

creator注解了工厂类的构造函数,可以用此方法反序列化后构造出对象。

public abstrat clientMapEntity{
       fromClient (Map<String, Object>, Type t){
               EntityFactory.getObjectMapper().convertValue(this, Map.class);
       }
}

3.3 其他如JsonIgnoreProperties.java

还有一些注解比如:忽略解析,不想解析输入的某些字段

@JsonIgnoreProperties("extra", "uselessValue")
public class Value {
        public int value;
}

这时可以解析这个json,不会报无法解析字段的异常,{“value”:42, "extra": "fluffy", "uselessValue": -12}

3.4 其他如JsonIgnore.java

不序列化到网络,不想输出

public class Value {
      public int value;
      @JsonIgnore
       public int internalValue
}. 

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券