jackson对json转化技巧
好多框架都使用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;
}
}
采用这种方式只需按需求文档定义好反序列化模板,在进行转化时会自动忽略除了模板中的数据以外其他的数据
----------------------------------------------------------------------------------------------------------------------------------
场景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相同
下一篇: 3款值得推荐的微信开发开源框架_PHP
推荐阅读
-
对python中xlsx,csv以及json文件的相互转化方法详解
-
对python中Json与object转化的方法详解
-
jackson对json转化技巧
-
将Datatable转化成json发送前台实现思路_javascript技巧
-
JS遍历Json字符串中键值对先转成JSON对象再遍历_javascript技巧
-
javascript对JSON数据排序的3个例子_javascript技巧
-
将Datatable转化成json发送前台实现思路_javascript技巧
-
JS解析json数据并将json字符串转化为数组的实现方法_javascript技巧
-
JS遍历Json字符串中键值对先转成JSON对象再遍历_javascript技巧
-
js定义对象或数组直接量时各浏览器对多余逗号的处理(json)_javascript技巧