zoukankan      html  css  js  c++  java
  • Jackson 通过自定义注解来控制json key的格式

    Jackson 通过自定义注解来控制json key的格式

    最近我这边有一个需求就是需要把Bean中的某一些特殊字段的值进行替换。而这个替换过程是需要依赖一个第三方的dubbo服务的。为了使得这个转换功能更加的通用,我们采用了下面的方式:

    • client端使用自定义的注解(假设为@Dimension)标记Bean中所有的「特殊字段」
    • client端把bean转换为json格式,但是这个转换过程的要求是:这些特殊的字段对应的json的key需要符合一定的格式,而这个格式依赖于标记的@Dimension注解
    • 然后client端通过dubbo RPC服务把json扔给server端,server进行一些json解析,替换之后把替换之后的json扔给client端,然后client端把接收到的json再转回为之前的Bean对象的实例。

    我们先来看看把bean转为json,一般没有特殊要求的话,我们都是:

     /**
         * Object可以是POJO,也可以是Collection或数组。
         * 如果对象为Null, 返回"null".
         * 如果集合为空集合, 返回"[]".
         *
         * @param object the object to json
         * @return toJson result
         */
        public String toJson(Object object) {
            try {
                return mapper.writeValueAsString(object);
            } catch (IOException e) {
                LOGGER.error("write to json string error:" + object, e);
                return null;
            }
        }
    

    这种是默认的情况,生成的json的key和对应的Bean的filed的name是一模一样的。

    而Jackson也给我们提供了注解:@JsonProperty注解来帮助我们重命名生成的json的key。但是他这个重命名并不是很灵活,因为他只能固定的重命名为某一个「确定的」值,而不能容许我们做一些额外的操作。

    所以在这种情况下,我打算自定义一个注解,因为业务场景相关,我们的注解定义如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Dimension {
        String valueType();
    }
    

    假设我们的json的key的生成规则如下:

    • valueType()的值为“id”时,json key追加后缀“_id”
    • valueType()的值为"code"时,json key追加后缀“_code”

    这个时候我们就可以使用Jackson提供给我们强大的JacksonAnnotationIntrospector类了。

    import com.google.common.base.Preconditions;
    import org.codehaus.jackson.Version;
    import org.codehaus.jackson.Versioned;
    import org.codehaus.jackson.map.introspect.AnnotatedField;
    import org.codehaus.jackson.map.introspect.JacksonAnnotationIntrospector;
    import org.codehaus.jackson.util.VersionUtil;
    
    import java.lang.annotation.Annotation;
    
    import static com.google.common.base.Strings.isNullOrEmpty;
    
    /**
     * @author rollenholt
     */
    public class DimensionFieldSerializer extends JacksonAnnotationIntrospector implements Versioned {
    
        @Override
        public Version version() {
            return VersionUtil.versionFor(getClass());
        }
    
    
        @Override
        public boolean isHandled(Annotation ann) {
            Class<?> cls = ann.annotationType();
            if (Dimension.class == cls) {
                return true;
            }
            return super.isHandled(ann);
        }
    
    
        @Override
        public String findSerializablePropertyName(AnnotatedField af) {
            return getPropertyName(af);
        }
    
        @Override
        public String findDeserializablePropertyName(AnnotatedField af) {
            return getPropertyName(af);
        }
    
        private String getPropertyName(AnnotatedField af) {
            Dimension annotation = af.getAnnotation(Dimension.class);
            if (annotation != null) {
                String valueType = annotation.valueType();
                Preconditions.checkArgument(!isNullOrEmpty(valueType), "@Dimension注解中的valudType不能为空");
                if (valueType.equalsIgnoreCase("id")) {
                    return af.getName() + "_id";
                }
                if (valueType.equalsIgnoreCase("code")) {
                    return af.getName() + "_code";
                }
            }
            return af.getName();
        }
    
    }
    
    
    

    同时为了触发上面的代码,以及为了验证我们的功能,我们有如下的代码:

    /**
     * @author rollenholt
     */
    public class DimensionAdapterHelper {
    
        private final static ObjectMapper objectMapper = new ObjectMapper();
    
        static {
            AnnotationIntrospector dimensionFieldSerializer = new DimensionFieldSerializer();
            objectMapper.setAnnotationIntrospector(dimensionFieldSerializer);
        }
    
        public static String beanToJson(Object object) {
            StringWriter sw = new StringWriter();
            try {
                objectMapper.writeValue(sw, object);
                return sw.toString();
            } catch (IOException e) {
                throw Throwables.propagate(e);
            }
        }
    
        public static <T> T jsonToBean(String json, Class<T> clazz) {
            try {
                return (T) objectMapper.readValue(json, clazz);
            } catch (IOException e) {
                throw Throwables.propagate(e);
            }
        }
    
    
        public static class Type {
            private String code;
    
            @Dimension(valueType = "id")
            private String description;
    
            @Dimension(valueType = "code")
            private String value;
    
            public Type() {
            }
    
            public Type(String code, String description, String value) {
                super();
                this.code = code;
                this.description = description;
                this.value = value;
            }
    
            public String getCode() {
                return code;
            }
    
            public void setCode(String code) {
                this.code = code;
            }
    
            public String getDescription() {
                return description;
            }
    
            public void setDescription(String description) {
                this.description = description;
            }
    
            public String getValue() {
                return value;
            }
    
            public void setValue(String value) {
                this.value = value;
            }
    
            @Override
            public String toString() {
                return ToStringBuilder.reflectionToString(this);
            }
        }
    
        public static void main(String[] args) {
            Type t = new Type("a", "b", "c");
            String json = beanToJson(t);
            System.out.println(json);
            Type type = jsonToBean(json, Type.class);
            System.out.println(type);
    
        }
    
    
    }
    
    

    运行之后输出结果为:

    {"code":"a","description_id":"b","value_code":"c"}
    DimensionAdapterHelper$Type@2cb4c3ab[code=a,description=b,value=c]
    

    还算是很符合我们的期望的。

    至于server端是如何替换json字符串的key的那块,简单的说一下,因为key有一定的格式,所以可以递归遍历json的所有key,就可以拿到有哪些key-value对需要处理了。关于如何在Java中递归便利Json,这个比较简单。如果大家觉的有需要,我后面在写。

    参考资料

  • 相关阅读:
    页面自动化
    phantomjs 开发爬虫框架
    javascript 正则表达式
    javascript/TypeScript 生成GUID
    Plupload 上传控件使用指南
    文件上传详解 (HTML FILE)
    Bootstrap File Input 中文文档
    找个地记录和分享工作上的点滴
    最短路 + 记录路径 之 zoj 1456 Minimum Transport Cost (hdu 1385)
    求解单源最短路问题:Bellman-Ford算法(可判负权回路)详解 之 poj 3268 Silver Cow Party
  • 原文地址:https://www.cnblogs.com/rollenholt/p/5406573.html
Copyright © 2011-2022 走看看