复杂JSON字符串转换为Java嵌套对象的方法

Posted 编程大观园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了复杂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 字符串解析出对应的数据模型 AgentDetectEventData:


@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) {
      return null;
    }
  }

  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);
      return null;
    }
  }
}

单测:


public class JsonUtilTest {

    @Test
    public void testParseJson() {
        try {
            String json = RWTool.readFromSource("/json.txt");
            List<AgentDetectEventData> ade = JsonUtil.jsonToObject(json, List.class, AgentDetectEventData.class);
            Assert.assertNotNull(ade);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

引入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() {
        try {
            String json = RWTool.readFromSource("/json.txt");
            List<AgentDetectEventData> ade = GsonUtil.fromJson(json, new TypeToken<List<AgentDetectEventData>>(){}.getType());
            Assert.assertNotNull(ade);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

引入 POM 为:


<dependency>
       <groupId>com.google.code.gson</groupId>
       <artifactId>gson</artifactId>
       <version>2.3.1</version>
</dependency>

以上是关于复杂JSON字符串转换为Java嵌套对象的方法的主要内容,如果未能解决你的问题,请参考以下文章

如何将复杂(嵌套)对象解析为 JSON 并在 Flutter 中使用 HTTP 将其发送到服务器?

Jackson 对象和JSON的相互转换

如何将json字符串转成带有对象引用的java对象

fastjson中怎么把java对象转化为json对象

android使用gson解析嵌套复杂的json数据,数据怎么显示到布局上,布局怎么写

Java自定义方法转换前端提交的json字符串为JsonObject对象