自定义 Jackson 注解与禁用某一特定的注解
来源:互联网 发布:程序员都用什么电脑 编辑:程序博客网 时间:2024/05/29 04:17
非常感谢 http://unmi.cc/customize-jackson-annotation-and-disable-specific-annotation/
- @JsonIgnore 此注解用于属性上,作用是进行JSON操作时忽略该属性。
- @JsonFormat 此注解用于属性上,作用是把Date类型直接转化为想要的格式,如@JsonFormat(pattern = "yyyy-MM-dd HH-mm-ss")。
- @JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化name,JsonProperty("name")。
- @JsonIgnoreProperties({"name","age"}),作用在类上,用来说明属性在序列化和反序列化时需要忽略掉。
- @JsonIgnoreProperties(ignoreUnknown=true)也可以注明在反序列化的时候过滤掉未知的属性,防止报错。
- @JsonUnwrapped作用在属性上,用来将子Json对象的属性添加到Json对象。
- @JsonUnwrapped作用在属性上,2.0+版本中添加了prefix和suffix属性,用在字段添加前后缀。
- @JsonNaming作用在类或方法上,作用和JsonProperty名称相同,同时也支持我们自己定制属性命名的策略。
- @JsonSerializer(using=MyDateSerializer.class),来指定序列化的实现,一般用于各种自定义的格式转换。
- @JsonDeserializer(using=MyDateDeserializer.class),来指定反序列化的实现,一般用于格式的转换。
- @JsonPropertyOrder(alphabetic=true,value={"c","b"}),序列化时对属性是否按字母顺序排序,默认不排序,value中的是优先其他排序的属性名称。
- 。。。。。很多灵活好用的注解,很强大
Jackson 是 Playfrmework 2 中默认的 JSON 处理框架,先前是 GSON,JSON 是 Playframework 中的第一等公民,可见 Jackson 在 Playframewok 中的重要地位。Jackson 提供了一系列的注解可用,像 @JsonIgnore, @JsonProperty, @JsonUnwrapped, @JsonFilter 等。人的需求总是很难得到满足,所以免不了还是要定义自己的注解。比如有这样一个需求,JavaBean 中被 @MaskField(这个即将成为我第一个自定义的注解) 标记的属性或 getter 方法,总是输出为 ******
, 无此标记的属性或方法输出原始值。
我尝试过 @JsonFilter 或是单纯的自定义 JsonSerializer, 并不怎么如意。本人最终的实现方式涉及到
- @JacksonAnnotationsInside -- 用来创建自己的 @MaskField 注解
- JsonSerializer -- 被 @MaskField 标记的字段采用自定义的 JsonSerializer 来序列化
- JacksonAnnotationIntrospector -- 禁用某一特定的注解,这样可以在做任意时候启用或禁用 @MaskField
再次重复需求,对于下面的 Person 类生成的对象
classPerson { publicString name = "Yanbin"; publicString getPhone () { return"(312)666-8888"; } publicint age = 100; @JsonProperty("city") publicString location = "Chicago"; }
想要对于某些用户生成
{"name":"Yanbin","age":"******","city":"Chicago","phone":"******"}
其他用户生成
{"name":"Yanbin","age":100,"city":"Chicago"}
即有条件的隐藏某些敏感信息。
希望自定义 @MaskField 来标 name 属性和 getPhone() 方法。
定义 @MaskField
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})@JacksonAnnotationsInside@JsonSerialize(using = MaskFieldSerializer.class)@interfaceMaskField {}
上面指示了标记为 @MaskField 字段或 getter 方法奖应用 MaskFieldSerializer 为序列化,总是输出为 ******
MaskFieldSerializer 类
classMaskFieldSerializer extendsJsonSerializer<Object> { @Override publicvoid serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throwsIOException { jgen.writeString("******"); }}
现在把 @MaskField 应用到 Person 类
classPerson { publicString name = "Yanbin"; @MaskField publicString phone () { return"(312)666-8888"; } @MaskField publicint age = 100; @JsonProperty("city") publicString location = "Chicago"; }
用代码测试一下
ObjectMapper maskMapper = newObjectMapper(); System.out.println(maskMapper.writeValueAsString(newPerson()));
输出结果没错了,就是
{"name":"Yanbin","age":"******","city":"Chicago","phone":"******"}
凡是标记了 @MaskField 的字段或 getter 方法最终输出统统为 ******, 还记得还有个需求是对于某些时候还希望看到原貌,即{"name":"Yanbin","age":100,"city":"Chicago"}
也就是有时要只禁用 @MaskField 注解。Jackson 可以调用
maskMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
来禁用所有的注解,那么像 @JsonProperty, @JsonIgnore 这样的注解如何是好,肯定不能一棍子打死,所以这里只是需要适时的把 @MaskField 禁用即可。这时候要用到 JacksonAnnotationIntrospector 来选择某个 Annotation 来禁用了。
因而自定义 DisablingMaskFieldIntrospector
classDisablingMaskFieldIntrospector extendsJacksonAnnotationIntrospector { @Override publicboolean isAnnotationBundle(Annotation ann) { if(ann.annotationType().equals(MaskField.class)) { returnfalse; }else{ returnsuper.isAnnotationBundle(ann); } } }
如果是 MaskField 就 return false, 禁用 @MaskField 注解
该告诉你的 ObjectMapper 使用这个自定义 AnnotationIntrospector,下面的测试代码
ObjectMapper showAllMapper = newObjectMapper();showAllMapper.setAnnotationIntrospector(newDisablingMaskFieldIntrospector());System.out.println(showAllMapper.writeValueAsString(newPerson()));
输出为
{"name":"Yanbin","age":100,"city":"Chicago"}
也就是要不要采用 DisablingMaskFieldIntrospector 就决定了我们禁止还是启用 @MaskField 注解的功能。
浪费点篇幅,上面完整的代码如下
importcom.fasterxml.jackson.annotation.*;importcom.fasterxml.jackson.core.*;importcom.fasterxml.jackson.databind.*;importcom.fasterxml.jackson.databind.annotation.JsonSerialize;importcom.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; importjava.io.IOException;importjava.lang.annotation.*; publicclass TestJacksonAnnotation { privatestatic ObjectMapper maskMapper = newObjectMapper(); privatestatic ObjectMapper showAllMapper = newObjectMapper() {{ setAnnotationIntrospector(newDisablingMaskFieldIntrospector()); }}; publicstatic void main(String[] args) throwsJsonProcessingException { System.out.println(maskMapper.writeValueAsString(newPerson())); System.out.println(showAllMapper.writeValueAsString(newPerson())); }} classPerson { publicString name = "Yanbin"; @MaskField publicString phone () { return"(312)666-8888"; } @MaskField publicint age = 100; @JsonProperty("city") publicString location = "Chicago"; } classMaskFieldSerializer extendsJsonSerializer<Object> { @Override publicvoid serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throwsIOException { jgen.writeString("******"); }} @Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})@JacksonAnnotationsInside@JsonSerialize(using = MaskFieldSerializer.class)@interfaceMaskField { } classDisablingMaskFieldIntrospector extendsJacksonAnnotationIntrospector { @Override publicboolean isAnnotationBundle(Annotation ann) { if(ann.annotationType().equals(MaskField.class)) { returnfalse; }else{ returnsuper.isAnnotationBundle(ann); } } }
执行后输出为
{"name":"Yanbin","age":"******","city":"Chicago","phone":"******"}
{"name":"Yanbin","age":100,"city":"Chicago"}
实际的操作就是根据不同的条件使用 maskMapper 或是 showAllMapper 来进行序列化。
参考:1. https://github.com/swagger-api/swagger-core/issues/982
- 自定义 Jackson 注解与禁用某一特定的注解
- jackson注解
- jackson注解
- 访问注解与自定义注解
- 注解的理解、自定义注解
- 自定义注解与使用
- jackson不拼null节点的注解
- AS3自定义注解的声明与使用
- spring 自定义注解的注册与扫描
- 自定义Java注解的方式与应用
- 自定义注解与spring事务的问题
- 自定义注解的学习与使用
- 自定义注解的学习与使用
- jackson使用--注解json
- Jackson注解学习参考
- jackson annotations注解详解
- Jackson常用注解介绍
- jackson注解使用
- 第一个C++程序
- C++实验报告1
- JAVA学习笔记之-继承
- DL 工作站配置
- Android复习-intent-filter匹配规则
- 自定义 Jackson 注解与禁用某一特定的注解
- Hello World 之程序人生
- Java 调用 Matlab并在Swing界面显示实例与心得总结
- [U3d][Animator]StateMachineBehaviour
- Python ping 实现(一)
- 腾讯云和腾讯云 挂载新的云磁盘
- centos 进程用户
- 使用zxing二维码
- 静态网页/动态网页/伪静态网页/动态HTML