jackson对json转化技巧

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wcandy001/article/details/79666991

好多框架都使用jackson工具进行json转化,现介绍一些使用技巧,本篇使用的jackson版本是2.4.2

涉及到的jar包:cglib-nodep-2.2.jar,jackson-annotations-2.4.2.jar,jackson-core-2.4.2.jar,jackson-databind-2.4.2.jar

本文以数据服务的角度针对后台ElasticSearch和客户需求的场景进行描述


场景1:ElasticSearch查询返回的数据信息太多了,远超过接口需求文档中要返回的信息,如图:


(buckets是个list,下面数据格式都相同,这里就不截图了)

而我方需求是:


可以看出只是某些嵌套中少了几个属性,这时使用jackson的@JsonIgnoreProperties注释可以实现自动忽略功能:使用方法如下,只需在类上面加一行就行

 
 
@JsonIgnoreProperties(ignoreUnknown = true)
public class BucketsT2 {
    String key;
    int doc_count;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public int getDoc_count() {
        return doc_count;
    }

    public void setDoc_count(int doc_count) {
        this.doc_count = doc_count;
    }
}

采用这种方式只需按需求文档定义好反序列化模板,在进行转化时会自动忽略除了模板中的数据以外其他的数据

扫描二维码关注公众号,回复: 5455122 查看本文章

----------------------------------------------------------------------------------------------------------------------------------

场景2:Elasticsearch查询返回的数据中针对key:value的数据格式较多,有时会发现 有些key会是:make.keyword,color.keyword这种,而反序列化模板要以key为属性名,如图:


这种样式的数据,java编写反序列化模板没法写,命名规则不允许有特殊字符,这就无法直接转换成对象(根本不能这么写)



那除了手动各种readTree一层层通过角标遍历抽出这部分数据以外还有个解决办法:

使用jackon的@JsonProperty注释,作用是当遇到指定属性名时自动转化为反序列化模板中的属性

@JsonIgnoreProperties(ignoreUnknown = true)
public class BucketsT {
    String key_as_string;
   // long key;
 //   int doc_count;
    @JsonProperty("make.keyword")
    Make make;
    @JsonProperty("color.keyword")
    Make color;

这就会把数据中的mak.keyword转化为mak存起来,同理color.keyword也一样

转化后,通过debug查看反序列化结果:


可以看到make.keyword已经存在了make中,这中方式就可以接收各种奇特的数据

--------------------------------------------------------------------------------------------------------------------------------

场景3:同样以ElasticSearch举例,一般json格式的反序列化模板,对于key:value是这么存的,key="",value="",这样存便于转化


但如果需求文档要求返回的格式是(可能这种格式不是一个好的方案,但是解决方案是要有的)


通过重写jackson Serializer过程,实现该功能,这里提供方法模板,可通过各种场景自定义具体处理逻辑:

首先我们要解决的问题:

1.参与序列化过程,让解析到该位置时,把red和1提取出来

2.动态生成一个类,加入red属性,赋值1

3.在序列化过程中返回新的类,即只替换了{key:red,doc_count:1}=>{read:1},其他整个json嵌套结构都没改变

(1)定义注释,定义序列化方法:

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


//JacksonAnnotationsInside用于创建注解,jasonSerialize用来指定序列化的类 
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@JacksonAnnotationsInside   
@JsonSerialize(using = TransformSerializer.class)
public @interface TransformField {
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import jackson_test.fieldmiss.object.BucketsT2;
import jackson_test.fieldmiss.object.DynamicBean;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;


public class TransformSerializer extends JsonSerializer<List<BucketsT2>> {
    @Override
    public void serialize(List<BucketsT2> old, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        //List<BucketsT2>表示我反序列化模板中的一个对象,如果需要修改String,int,或各种类型都可以,替换第一个参数的类型就行
       ArrayList<Object> list=new ArrayList<>();
        for(BucketsT2 temp:old){
            //获取key的值:red
            String key=temp.getKey();
            //获取count的值:1
            Integer value=temp.getDoc_count();
            //定义动态生成类的属性模板,map中存的数据格式为(属性名,属性类型的class)
            HashMap<String,Class> map=new HashMap<>();
            //(red,Integer.class)
            map.put(key,value.getClass());
            //传给对象生成器
            DynamicBean bean=new DynamicBean(map);
            //把属性值传递给生成器(red,1),会自动把1付给red属性
            bean.setValue(key,value);
            //getObject获得一个拥有一个read属性的类
            list.add(bean.getObject());
        }
        //替换了本来old数据的返回结果
        jsonGenerator.writeObject(list);

    }
}

(2)动态生成类

import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class DynamicBean {

    private  Object object = null;//动态生成的类
    private  BeanMap beanMap = null;//存放属性名称以及属性的类型

    public DynamicBean() {
        super();
    }

    @SuppressWarnings("rawtypes")
    public DynamicBean(Map propertyMap) {
        this.object = generateBean(propertyMap);
        this.beanMap = BeanMap.create(this.object);
    }

    /**
     * 给bean属性赋值
     * @param property 属性名
     * @param value 值
     */
    public void setValue(Object property, Object value) {
        beanMap.put(property, value);
    }

    /**
     * 通过属性名得到属性值
     * @param property 属性名
     * @return 值
     */
    public Object getValue(String property) {
        return beanMap.get(property);
    }

    /**
     * 得到该实体bean对象
     * @return
     */
    public Object getObject() {
        return this.object;
    }

    /**
     * @param propertyMap
     * @return
     */
    @SuppressWarnings("rawtypes")
    private Object generateBean(Map<String,Class> propertyMap) {
        BeanGenerator generator = new BeanGenerator();
        Set keySet = propertyMap.keySet();
        for (Iterator i = keySet.iterator(); i.hasNext();) {
            String key = (String) i.next();
            Class class_name=propertyMap.get(key);
            generator.addProperty(key,class_name);
        }
        return generator.create();
    }

}

最后的使用方法:


只需在要转化的对象上加一个注解,这里注意buckets的类型一定要与Serializer相同



猜你喜欢

转载自blog.csdn.net/wcandy001/article/details/79666991