好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

复杂JSON字符串转换为Java嵌套对象的实现

背景

实际开发中,常常需要将比较复杂的 JSON 字符串转换为对应的 Java 对象。这里记录下解决方案。

如下所示,是入侵事件检测得到的 JSON 串:

[{"rule_id":"反弹shell","format_output":"进程 pname 反向连接到 %dest_ip%:%dest_port%","info":{"process_events":{"pid":21,"pname":"nginx","cmdline":"curl HdhCmsTestcfda测试数据","ppid":7,"ppname":"bash"},"proc_trees":[{"pid":21,"pname":"nginx","cmdline":"curl HdhCmsTestcfda测试数据","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 串便于后续解析。

?

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());

     }

}

构建对象模型

首先,要根据这个 JSON 字符串解析出对应的数据模型 AgentDetectEventData。主要就是按照 JSON 串中的 key 的层次结构来建立。

?

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;

}

这里有两个注意点:

JSON 字符串的字段命名是下划线形式,而 Java 对象的属性命名是驼峰式的,这里需要做一个字段名映射转换。 使用 Jackson 库来转换,是 @JsonProperty 注解; 使用 gson 库来转换,是 @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 );

     // 序列化的时候,跳过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());

     }

   }

}

单测:

?

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 入参的方法:

?

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\":\"认养一头牛\"},\"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://HdhCmsTestcnblogs测试数据/lovesqcc/p/14798434.html

查看更多关于复杂JSON字符串转换为Java嵌套对象的实现的详细内容...

  阅读:45次