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,这个比较简单。如果大家觉的有需要,我后面在写。

    参考资料

  • 相关阅读:
    泛微云桥e-Bridge 目录遍历,任意文件读取
    (CVE-2020-8209)XenMobile-控制台存在任意文件读取漏洞
    selenium 使用初
    将HTML文件转换为MD文件
    Python对word文档进行操作
    使用java安装jar包出错,提示不是有效的JDK java主目录
    Windows server 2012安装VM tools异常解决办法
    ifconfig 命令,改变主机名,改DNS hosts、关闭selinux firewalld netfilter 、防火墙iptables规则
    iostat iotop 查看硬盘的读写、 free 查看内存的命令 、netstat 命令查看网络、tcpdump 命令
    使用w uptime vmstat top sar nload 等命令查看系统负载
  • 原文地址:https://www.cnblogs.com/rollenholt/p/5406573.html
Copyright © 2011-2022 走看看