需求
最近接入了两种只有一个字段名称不一致的json日志数据,因为数据存放在Kafka中,目的是留存成文件加载数据库,不假思索决定Flume来完成这个需求。 按照常理的做法肯定是定义两个实体类,定义两个Interceptor来解析。但是懒人自有天相,最近抛弃了fastjson的我决定拥抱Gson,定义一个实体类和Interceptor来解析。实体类代码如下:
public class ReqDomain {
private String op_time;
@SerializedName(value = "inContent", alternate = {"outContent"})
private String content;
private String type;
@SerializedName("@timestamp")
private String timestamp;
}
@SerializedName的value属性是序列化和反序列化的字段名称。
alternate是反序列化时没有value对应的字段名的时候的才会用到的备胎名集合
例如定义两个json格式的字符串
String str1 = "{\"inContent\": \"Hello World\"}";
String str2 = "{\"outContent\": \"Hello World\"}";
Gson gson = new Gson();
从字符串转换成实体实体类的过程就是反序列化:
// 输出req1和req2的content,均为Hello World
// str1有inContent属性,所以直接将它的值赋给content
ReqDomain req1 = json.fromJson(str1, ReqDomain.class);
// str2没有inContent属性,就会去找备胎outContent赋值给content
ReqDomain req2 = json.fromJson(str2, ReqDomain.class);
从实体类转换成json的过程就是序列化:
// 输出json1和json2均为{"inContent": "Hello World"}
String json1 = gson.toJson(req1);
String json2 = gson.toJson(req2);
不难看出,value属性的inContent参与了序列化和反序列化,alternate里面的备胎outContent只参与了反序列化。
信心满满的对上面@SerializedName的用法了如指掌的时候,outContent字段解析出来的是null,我以为是忘记了编译,clean之后再次package,发现输出还是null。 因为outContent字段特别长,记得flume中有个event(数据)最大限制,我就去查看flume打印的日志,没有报错!!! 在本机写了个demo发现outContent是可以正常解析的。难道是代码灵异事件????查找多处资料后,发现
alternate只有在2.4版本之后才能使用
本地使用的Gson2.8,并且将依赖打进了jar包,但是flume中lib下居然有个gson-2.2.2.jar(奔溃中...),根据java的类加载原理,gson2.2加载之后就不会加载gson2.8中重复的class,在删除了gson-2.2.2.jar之后,小手一阵敲打,jps -m | grep xxx | xargs kill -9并sh xxx.sh重启flume,完成解析!!
以下的代码也可以解决上面的难题,遗憾Flume不支持python实现......
import json
str1 = "{\"inContent\": \"Hello World\"}"
str2 = "{\"outContent\": \"Hello World\"}"
# 两行代码皆会输出 Hello World
print(json.loads(str1)['inContent'])
print(json.loads(str2)['outContent'])