背景
實(shí)際開發(fā)中,常常需要將比較復(fù)雜的 JSON 字符串轉(zhuǎn)換為對應(yīng)的 Java 對象。這里記錄下解決方案。
如下所示,是入侵事件檢測得到的 JSON 串:
[{"rule_id":"反彈shell","format_output":"進(jìn)程 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"}}}]
方法
預(yù)備工作
把上述 json 串放在 src/test/resources 下,寫一個(gè)文件讀寫程序來解析。 其實(shí)放在哪里不重要,重要的是拿到這個(gè) JSON 串便于后續(xù)解析。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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()); } } |
構(gòu)建對象模型
首先,要根據(jù)這個(gè) JSON 字符串解析出對應(yīng)的數(shù)據(jù)模型 AgentDetectEventData。主要就是按照 JSON 串中的 key 的層次結(jié)構(gòu)來建立。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
@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; } |
這里有兩個(gè)注意點(diǎn):
- JSON 字符串的字段命名是下劃線形式,而 Java 對象的屬性命名是駝峰式的,這里需要做一個(gè)字段名映射轉(zhuǎn)換。 使用 Jackson 庫來轉(zhuǎn)換,是 @JsonProperty 注解; 使用 gson 庫來轉(zhuǎn)換,是 @SerializedName 注解。
- 需要加 getter / setter 方法。
對象模型建立后,就成功了一大半。接下來,就是使用 json 庫來解析了。
使用jackson 庫解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
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 ); // 序列化的時(shí)候,跳過null值 MAPPER.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); // date類型轉(zhuǎn)化 SimpleDateFormat fmt = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); MAPPER.setDateFormat(fmt); } /** * 將一個(gè)json字符串解碼為java對象 * * 注意:如果傳入的字符串為null,那么返回的對象也為null * * @param json json字符串 * @param cls 對象類型 * @return 解析后的java對象 * @throws RuntimeException 若解析json過程中發(fā)生了異常 */ 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()); } } } |
單測:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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依賴為:
1
2
3
4
5
|
< dependency > < groupId >org.codehaus.jackson</ groupId > < artifactId >jackson-mapper-asl</ artifactId > < version >1.9.4</ version > </ dependency > |
使用GSON解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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); } } |
單測:
1
2
3
4
5
6
7
8
|
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 為:
1
2
3
4
5
|
< dependency > < groupId >com.google.code.gson</ groupId > < artifactId >gson</ artifactId > < version >2.3.1</ version > </ dependency > |
不含列表的嵌套對象
如果是不含列表的嵌套對象,則使用帶 Class cls 入?yún)⒌姆椒ǎ?/p>
1
2
3
4
5
6
7
8
9
10
11
12
|
@Test public void testParseSimpleNestedJson() { String json = "{\"goods\":{\"desc\":\"2箱*250g\",\"goodsId\":8866,\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"title\":\"認(rèn)養(yǎng)一頭牛\"},\"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\":\"認(rèn)養(yǎng)一頭牛\"},\"order\":{\"bookTime\":1621656157,\"codPay\":false,\"deliveryType\":\"express\",\"orderNo\":\"E20210522120237009258\",\"shopId\":659494,\"userId\":1476}}" ; BookInfo bookInfo = GsonUtil.fromJson(json, BookInfo. class ); Assert.assertNotNull(bookInfo); } |
讀者可以自行解析出 BookInfo 的對象模型。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://www.cnblogs.com/lovesqcc/p/14798434.html