复杂JSON字符串转换为Java嵌套对象的实现
作者:琴水玉 发布时间:2023-07-02 05:40:26
背景
实际开发中,常常需要将比较复杂的 JSON 字符串转换为对应的 Java 对象。这里记录下解决方案。
如下所示,是入侵事件检测得到的 JSON 串:
[{"rule_id":"反弹shell","format_output":"进程 pname 反向连接到 %dest_ip%:%dest_port%","info":{"process_events":{"pid":21,"pname":"nginx","cmdline":"curl www.cfda.com","ppid":7,"ppname":"bash"},"proc_trees":[{"pid":21,"pname":"nginx","cmdline":"curl www.cfda.com","ppid":7,"ppname":"bash"}],"containers":{"container_id":"fef4636d8403871c2e56e06e51d609554564adbbf8284dd914a0f61130558bdf","container_name":"nginx","image_id":"4eb8f7c43909449dbad801c50d9dccc7dc86631e54f28b1a4b13575729065be8","status":"Running"},"sockets":{"src_ip":"127.0.0.1","src_port":"8080","type":"1","in_out":"0","dest_ip":"localhost","dest_port":"80"}}}]
方法
预备工作
把上述 json 串放在 src/test/resources 下,写一个文件读写程序来解析。 其实放在哪里不重要,重要的是拿到这个 JSON 串便于后续解析。
public static String readFromSource(String filename) {
try {
InputStream is = RWTool.class.getResourceAsStream(filename);
byte[] bytes = new byte[4096];
int num = 0;
String json = "";
while((num=is.read(bytes))>0){
json=new String(bytes,0,num);
}
return json;
} catch (Exception ex) {
throw new RuntimeException(ex.getCause());
}
}
构建对象模型
首先,要根据这个 JSON 字符串解析出对应的数据模型 AgentDetectEventData。主要就是按照 JSON 串中的 key 的层次结构来建立。
@Getter
@Setter
public class AgentDetectEventData {
@SerializedName("rule_id")
@JsonProperty("rule_id")
private String ruleId;
@SerializedName("format_output")
@JsonProperty("format_output")
private String formatOutput;
@SerializedName("info")
@JsonProperty("info")
private AgentDetectEventDetail info;
}
@Getter
@Setter
public class AgentDetectEventDetail {
@SerializedName("process_events")
@JsonProperty("process_events")
private ProcessEvent processEvent;
@SerializedName("proc_trees")
@JsonProperty("proc_trees")
private List<ProcessTree> procTree;
@SerializedName("containers")
@JsonProperty("containers")
private Container container;
@SerializedName("sockets")
@JsonProperty("sockets")
private Socket socket;
}
@Getter
@Setter
public class ProcessEvent {
@SerializedName("pid")
@JsonProperty("pid")
private String pid;
@SerializedName("pname")
@JsonProperty("pname")
private String pname;
@SerializedName("cmdline")
@JsonProperty("cmdline")
private String cmdline;
@SerializedName("ppid")
@JsonProperty("ppid")
private String ppid;
@SerializedName("ppname")
@JsonProperty("ppname")
private String ppname;
}
@Getter
@Setter
public class ProcessTree {
@SerializedName("pid")
@JsonProperty("pid")
private String pid;
@SerializedName("pname")
@JsonProperty("pname")
private String pname;
@SerializedName("cmdline")
@JsonProperty("cmdline")
private String cmdline;
@SerializedName("ppid")
@JsonProperty("ppid")
private String ppid;
@SerializedName("ppname")
@JsonProperty("ppname")
private String ppname;
}
@Getter
@Setter
public class Container {
@SerializedName("container_id")
@JsonProperty("container_id")
private String containerId;
@SerializedName("container_name")
@JsonProperty("container_name")
private String containerName;
@SerializedName("image_id")
@JsonProperty("image_id")
private String imageId;
@SerializedName("status")
@JsonProperty("status")
private String status;
}
@Getter
@Setter
public class Socket {
@SerializedName("src_ip")
@JsonProperty("src_ip")
private String srcIp;
@SerializedName("src_port")
@JsonProperty("src_port")
private String srcPort;
@SerializedName("type")
@JsonProperty("type")
private String type;
@SerializedName("in_out")
@JsonProperty("in_out")
private String inOut;
@SerializedName("dest_ip")
@JsonProperty("dest_ip")
private String destIp;
@SerializedName("dest_port")
@JsonProperty("dest_port")
private String destPort;
}
这里有两个注意点:
JSON 字符串的字段命名是下划线形式,而 Java 对象的属性命名是驼峰式的,这里需要做一个字段名映射转换。 使用 Jackson 库来转换,是 @JsonProperty 注解; 使用 gson 库来转换,是 @SerializedName 注解。
需要加 getter / setter 方法。
对象模型建立后,就成功了一大半。接下来,就是使用 json 库来解析了。
使用jackson 库解析
public class JsonUtil {
private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
// 为保持对象版本兼容性,忽略未知的属性
MAPPER.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 序列化的时候,跳过null值
MAPPER.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
// date类型转化
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
MAPPER.setDateFormat(fmt);
}
/**
* 将一个json字符串解码为java对象
*
* 注意:如果传入的字符串为null,那么返回的对象也为null
*
* @param json json字符串
* @param cls 对象类型
* @return 解析后的java对象
* @throws RuntimeException 若解析json过程中发生了异常
*/
public static <T> T toObject(String json, Class<T> cls) {
if (json == null) {
return null;
}
try {
return MAPPER.readValue(json, cls);
} catch (Exception e) {
throw new RuntimeException(e.getCause());
}
}
public static <T> String objectToJson(T obj){
if(obj == null){
return null;
}
try {
return obj instanceof String ? (String) obj : MAPPER.writeValueAsString(obj);
} catch (Exception e) {
return null;
}
}
public static <T> T jsonToObject(String src, TypeReference<T> typeReference){
if(StringUtils.isEmpty(src) || typeReference == null){
return null;
}
try {
return (T)(typeReference.getType().equals(String.class) ? src : MAPPER.readValue(src, typeReference));
} catch (Exception e) {
logger.warn("Parse Json to Object error",e);
throw new RuntimeException(e.getCause());
}
}
public static <T> T jsonToObject(String src, Class<?> collectionClass,Class<?>... elementClasses){
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(collectionClass,elementClasses);
try {
return MAPPER.readValue(src, javaType);
} catch (Exception e) {
logger.warn("Parse Json to Object error",e);
throw new RuntimeException(e.getCause());
}
}
}
单测:
public class JsonUtilTest {
@Test
public void testParseJson() {
String json = RWTool.readFromSource("/json.txt");
List<AgentDetectEventData> ade = JsonUtil.jsonToObject(json, new TypeReference<List<AgentDetectEventData>>() {});
Assert.assertNotNull(ade);
}
@Test
public void testParseJson2() {
String json = RWTool.readFromSource("/json.txt");
List<AgentDetectEventData> ade = JsonUtil.jsonToObject(json, List.class, AgentDetectEventData.class);
Assert.assertNotNull(ade);
}
}
引入POM依赖为:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>
使用GSON解析
public class GsonUtil {
static GsonBuilder gsonBuilder = null;
static {
gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss");
}
public static Gson getGson() {
return gsonBuilder.create();
}
public static <T> T fromJson(String json, Class<T> cls) {
return getGson().fromJson(json, cls);
}
public static <T> T fromJson(String json, Type type) {
return getGson().fromJson(json, type);
}
}
单测:
public class GsonUtilTest {
@Test
public void testParseJson() {
String json = RWTool.readFromSource("/json.txt");
List<AgentDetectEventData> ade = GsonUtil.fromJson(json, new TypeToken<List<AgentDetectEventData>>(){}.getType());
Assert.assertNotNull(ade);
}
}
引入 POM 为:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.3.1</version>
</dependency>
不含列表的嵌套对象
如果是不含列表的嵌套对象,则使用带 Class cls 入参的方法:
@Test
public void testParseSimpleNestedJson() {
String json = "{\"goods\":{\"desc\":\"2箱*250g\",\"goodsId\":8866,\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"title\":\"认养一头牛\"},\"order\":{\"bookTime\":1621656157,\"codPay\":false,\"deliveryType\":\"express\",\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"userId\":1476}}";
BookInfo bookInfo = JsonUtil.toObject(json, BookInfo.class);
Assert.assertNotNull(bookInfo);
}
@Test
public void testParseSimpleNestedJson() {
String json = "{\"goods\":{\"desc\":\"2箱*250g\",\"goodsId\":8866,\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"title\":\"认养一头牛\"},\"order\":{\"bookTime\":1621656157,\"codPay\":false,\"deliveryType\":\"express\",\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"userId\":1476}}";
BookInfo bookInfo = GsonUtil.fromJson(json, BookInfo.class);
Assert.assertNotNull(bookInfo);
}
读者可以自行解析出 BookInfo 的对象模型。
来源:https://www.cnblogs.com/lovesqcc/p/14798434.html
猜你喜欢
- Android 中ScrollView嵌套GridView,ListView的实例在Android开发中,经常有一些UI需要进行固定styl
- 1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1)
- 图像滤波在opencv中可以有多种实现形式自定义滤波如使用3×3的掩模:对图像进行处理.使用函数filter2D()实现#include&l
- 前言我们在学习Windows应用程序开发中,经常会用到消息对话框给用户或者管理员一些的消息提示,它们都是基于对MessageBox类的消息对
- 前言前面介绍了APP顶部导航栏AppBar,今天来介绍下Flutter实现APP底部导航栏。我们以仿写微信的底部导航栏来举例说明。要实现类似
- [LeetCode] 159. Longest Substring with At Most Two Distinct Characters
- 1. 前言现在很多应用都有小悬浮窗的功能,比如看直播的时候,通过Home键返回桌面,直播的小窗口仍可以在屏幕上显示。下面将介绍下悬浮窗的的一
- 可以静态绑定数据源,这样就自动为DataGridView控件添加 相应的行。假如需要动态为DataGridView控件添加新行,方法有很多种
- 最近碰到个需求,是希望在Unity有一个按钮,打开后直接跳转淘宝app,打开商品页面。百度了下没有相关的文章,于是我在此分享下。之前开发游戏
- 接收到这样一个需求,就是英文名字中firstName和lastName,其中任何一个为null,就返回Empty。刚拿到需求,这不简单,if
- 在Linux中创建一个新进程的唯一方法是使用fork()函数。fork()函数是Linux中一个非常重要的函数,和以往遇到的函数有一些区别,
- 引语:工作中有时候需要在普通的对象中去调用spring管理的对象,但是在普通的java对象直接使用@Autowired或者@Resource
- 为什么要使用路由在之前我们的代码中,页面跳转使用的代码如下所示:Navigator.of(context).push( Mate
- 1.返回ModelAndView对象(.jsp)controller代码:package controller;import java.ut
- 目录Android 集成Flutter1, Hello Flutter2, 引入 Flutter 模块3,使用Flutter3.1 添加依赖
- 本文主要介绍我为桌面和 Web 设计的一个超级秘密 Flutter 项目使用了画布和可拖动节点界面。本教程将展示我如何使用堆栈来使用小部件完
- 更新了AS 3.1.2之后,发现新建Kotlin类,类注释依然木有,没办法只有自己动手了。方法很简单,编辑File Header就可以啦。只
- 静态库和动态库的区别1、静态库的扩展名一般为".a"或者".lib";动态库的扩展名一般为"
- 在我们实现某些功能时,可能会有倒计时的需求。比如发送短信验证码,发送成功后可能要求用户一段时间内不能再次发送,这时候我们就需要进行倒计时,时
- 目录多选和单选的不同之处实现方式界面变更代码实现总结多选和单选的不同之处单选的时候,选中一个就可以直接把结果返回,因此本身底部弹窗无需状态管