热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

这篇文章主要介绍了复杂JSON字符串转换为Java嵌套对象的实现,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完

复杂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 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 toObject(String json, Class cls) {
    if (json == null) {
      return null;
    }
    try {
      return MAPPER.readValue(json, cls);
    } catch (Exception e) {
      throw new RuntimeException(e.getCause());
    }
  }
  public static  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 jsonToObject(String src, TypeReference 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 jsonToObject(String src, Class<&#63;> collectionClass,Class<&#63;>... 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 ade = JsonUtil.jsonToObject(json, new TypeReference>() {});
        Assert.assertNotNull(ade);
    }
    @Test
    public void testParseJson2() {
        String json = RWTool.readFromSource("/json.txt");
        List ade = JsonUtil.jsonToObject(json, List.class, AgentDetectEventData.class);
        Assert.assertNotNull(ade);
    }
}

引入POM依赖为:


       org.codehaus.jackson
       jackson-mapper-asl
       1.9.4

使用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 fromJson(String json, Class cls) {
    return getGson().fromJson(json, cls);
  }
  public static  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 ade = GsonUtil.fromJson(json, new TypeToken>(){}.getType());
        Assert.assertNotNull(ade);
    }
}

引入 POM 为:


       com.google.code.gson
       gson
       2.3.1

不含列表的嵌套对象

如果是不含列表的嵌套对象,则使用带 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 的对象模型。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程笔记。


推荐阅读
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • ZABBIX 3.0 配置监控NGINX性能【OK】
    1.在agent端查看配置:nginx-V查看编辑时是否加入状态监控模块:--with-http_stub_status_module--with-http_gzip_stat ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 从U ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • 在加载一个第三方厂商的dll文件时,提示“找不到指定模块,加载失败”。由于缺乏必要的技术支持,百思不得期间。后来发现一个有用的工具 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了markdown[软件代理设置]相关的知识,希望对你有一定的参考价值。 ... [详细]
  • (1)使用vi工具vitest.sh(2)利用如下命令查看文件格式:setff或:setfileformat可以看到如下信息 ... [详细]
  • 这篇文章给大家介绍怎么从源码启动和编译IoTSharp ,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。IoTSharp项目是 ... [详细]
  • 【BP靶场portswigger服务端10】XML外部实体注入(XXE注入)9个实验(全)
    前言:介绍:博主:网络安全领域狂热爱好者(承诺在CSDN永久无偿分享文章)。殊荣:CSDN网络安 ... [详细]
  •   一直对shell脚本有一种特殊的感觉,因此花了一段时间学习,本人擅长C语言编程,深受C语言荼毒,在学习其他任何类似于编程语言的东东的时候,都会不自觉的与C进行对比,因此对于shell中的变量的作用 ... [详细]
author-avatar
小小伟
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有