摘要
我曾经写过一篇Spring boot里面使用fastJson自定义属性注解实现个性化的处理null并返回其他值的实现方式,本文讲解在jackson中如何实现通过注解自定义Null返回的值。
我曾经写过一篇Spring boot里面使用fastJson自定义属性注解实现个性化的处理null并返回其他值的实现方式,本文讲解在jackson中如何实现通过注解自定义Null返回的值。
本次实现的需求如下:
1、只有注解、注解只有默认值 :值为null时-Double、Integer、Float、Long:0、,Charract:'',String:"",Boolean:true,List、Map、Set:空集合
2、注解有默认值(可以包含null)和标签时:当值符合标签中的值时,返回默认值,否则返回原值
该接口中有两个字段:tags,defaultVal,分别用来设置符合的值和一旦命中符合的值,要返回的值
package com.example.demo.aop; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; import com.fasterxml.jackson.databind.annotation.JsonSerialize; /** * 1、tags 不填,defaultVal 填写啥就返回啥 * 2、tags 不填,defaultVal 不填写则返回原值 * 3、tags 填写,defaultVal 不填写则返回原值 * 4、tags 填写,defaultVal填写,如果原值和tags中匹配,则返回defaultVal,否则返回原值 * 5、只针对8中包装类型,其余类型属性不得使用 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD, ElementType.METHOD}) @JacksonAnnotationsInside @JsonSerialize(using = MaskFieldSerializer.class) //@JsonSerialize(using = MyExpressionDeserializer.class) public @interface DefaultFieldVal { //哪些标签需要转换 String [] tags() default {}; //要转换的值 String defaultVal() default ""; }
package com.example.demo.aop; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import com.example.demo.StringUtils; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.ContextualSerializer; import org.assertj.core.util.Lists; import org.springframework.util.CollectionUtils; public class MaskFieldSerializer extends JsonSerializer<Object> implements ContextualSerializer { private String [] tags; private String defaultVal; // 必须要保留无参构造方法 public MaskFieldSerializer () { super(); } public MaskFieldSerializer(String[] tags, String defaultVal) { this.tags = tags; this.defaultVal = defaultVal; } @Override public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException { //list,值判断为空时赋值,否则返回原值 if (value instanceof List) { if (value == null) { List tmp = new ArrayList(); jgen.writeObject(tmp); } else { jgen.writeObject(value); } return ; } List<String> allTagList = Lists.newArrayList(tags).stream().map(e -> e).collect(Collectors.toList()); if (CollectionUtils.isEmpty(allTagList)) { if (defaultVal == null) { //2、tags 不填,defaultVal 不填写则返回原值 jgen.writeObject(value); } else { //1、tags 不填,defaultVal 填写啥就返回啥 jgen.writeObject(defaultVal); } return ; } //3、tags 填写,defaultVal 不填写则返回原值 if (defaultVal == null) { jgen.writeObject(value); return ; } //4、tags 填写,defaultVal填写,如果原值和tags中匹配,则返回defaultVal,否则返回原值 String tmpStr = null; if (value == null) { tmpStr = "null"; } else { tmpStr = String.valueOf(value); } if (allTagList.contains(tmpStr)) { if (StringUtils.isNotBlank(defaultVal)) { jgen.writeObject(defaultVal); } else { jgen.writeObject(value); } } else { String currentName = jgen.getOutputContext().getCurrentName(); System.out.println(currentName); jgen.writeObject(value); } } /** * 获取field的注解信息 * @param serializerProvider provider * @param beanProperty 实体类的属性 * @return * @throws JsonMappingException */ @Override public JsonSerializer<?> createContextual(SerializerProvider serializerProvider, BeanProperty beanProperty) throws JsonMappingException { if (beanProperty != null) { // 为空直接跳过 DefaultFieldVal defaultFieldVal = beanProperty.getAnnotation (DefaultFieldVal.class); if (defaultFieldVal == null) { defaultFieldVal = beanProperty.getContextAnnotation (DefaultFieldVal.class); } if (defaultFieldVal != null) { // 如果能得到注解,就将注解的 value 传入 ImageURLSerialize return new MaskFieldSerializer (defaultFieldVal.tags(),defaultFieldVal.defaultVal()); } } return serializerProvider.findValueSerializer (beanProperty.getType (), beanProperty); } }
上面两个类即可实现上述业务需求。
下面是测试类
package com.example.demo.entity; import java.math.BigDecimal; import java.util.Date; import java.util.List; import com.example.demo.aop.DefaultFieldVal; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; @Data public class TestResponse { @DefaultFieldVal(tags = {"李四"} , defaultVal = "测试为李四的默认值") private String name; @DefaultFieldVal(tags = {"null","sds"} , defaultVal = "测试为值") private String fullName; @JsonProperty("Addr") @DefaultFieldVal(tags = {"aaa","null"} , defaultVal = "测试变化") private String addr; @DefaultFieldVal(tags = {"1","2"} , defaultVal = "小孩子") private Integer age; @DefaultFieldVal(defaultVal = "男士") private Boolean isMen; @DefaultFieldVal(tags = {"null"} , defaultVal = "true") private Boolean exists; @DefaultFieldVal(defaultVal = "99.9") private Double scode; @DefaultFieldVal(tags = {"true", "false"} , defaultVal = "true") private Boolean userStatus; @DefaultFieldVal(tags = {"221.1"} , defaultVal = "32.9") private BigDecimal price; @DefaultFieldVal private List<Integer> aaList; @DefaultFieldVal( defaultVal = "2021-23-22") private Date currentDate; }
package com.example.demo.controller; import com.example.demo.entity.TestResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "/test") public class TestJsonDefaultController { @RequestMapping(value = "/getDealerLicense") @ResponseBody public TestResponse getDealerLicense(String name,String fullName) { TestResponse testResponse = new TestResponse(); testResponse.setName(name); testResponse.setFullName(fullName); testResponse.setAddr("aaa"); testResponse.setAge(12); testResponse.setIsMen(null); testResponse.setExists(true); testResponse.setCurrentDate(null); return testResponse; } }
通过上述代码就能实现上述业务。
注意:这只是一个技巧和方式,能实现业务,但是里面有部分逻辑问题,具体实现请自己斟酌后再加入到自己的项目中,。