软件编程
位置:首页>> 软件编程>> java编程>> 复杂JSON字符串转换为Java嵌套对象的实现

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

作者:琴水玉  发布时间:2023-07-02 05:40:26 

标签:JSON,字符串,Java,嵌套对象

背景

实际开发中,常常需要将比较复杂的 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

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com