文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何构建一个JSON字符串

2023-05-31 00:11

关注

本篇文章给大家分享的是有关如何构建一个JSON字符串,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

一、alibaba 的 Fastjson

Fastjson 是一个以 Java 语言编写的 JSON 处理器,由阿里巴巴公司开发,功能强大。

要使用第三方的工具当然要导入 jar 包了,只需导入 fastjson-1.2.8.jar 即可,jar 包的获取,大家可以直接去网上下载 ,也可以联系本人。

先来一个 fastjson 的简单实例吧,如下代码构造了一个 Customer 的实例,并将此实例转化成为 JSON 字符串,调用了 com.alibaba.fastjson.JSON 的 toJSONString() 方法,将 Customer 实例传入

@Testpublic void test1() {  Customer customer = new Customer(); customer.setId(1); customer.setCustName("Tom"); customer.setAddress("BeiJing");  String jsonStr = JSON.toJSONString(customer); System.out.println(jsonStr);}

打印结果:{"address":"BeiJing","custName":"Tom","id":1}

再来一个小测试,将一个 List 的 Customer 的集合转换为 JSON 字符串,22 行还是直接调用 JSON 的 toJSONString() 方法,将 List 集合传入即可

@Testpublic void test2() { List<Customer> lists = new ArrayList<>();  Customer customer = new Customer(); customer.setId(1); customer.setCustName("Tom"); customer.setAddress("BeiJing");  lists.add(customer);  Customer customer2 = new Customer(); customer2.setId(1); customer2.setCustName("Bob"); customer2.setAddress("ShangHai");  lists.add(customer2);  String jsonStr = JSON.toJSONString(lists); System.out.println(jsonStr);}

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}]

深入研究一下,我们看下面这种情况:3 行创建了一个 List 的 Customer 集合,10 和 11 行进行了一个重复的 add 操作,那么打印结果是什么样的呢?

@Testpublic void test3() { List<Customer> lists = new ArrayList<>(); Customer customer = new Customer(); customer.setId(1); customer.setCustName("Tom"); customer.setAddress("BeiJing"); lists.add(customer); lists.add(customer);  String jsonStr = JSON.toJSONString(lists); System.out.println(jsonStr);}

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"$ref":"$[0]"}],大家看,第二个 Customer 实例没有打印出,这就证明了 fastjson 默认禁止循环的引用,如果想改变这种情况,需要在 JSON 的 toJSONString() 方法中传递第二个参数 SerializerFeature.DisableCircularReferenceDetect 即可解决,如下:

@Testpublic void test3() {  List<Customer> lists = new ArrayList<>();  Customer customer = new Customer();  customer.setId(1);  customer.setCustName("Tom");  customer.setAddress("BeiJing");  lists.add(customer);  lists.add(customer);   String jsonStr = JSON.toJSONString(lists, SerializerFeature.DisableCircularReferenceDetect);  System.out.println(jsonStr);}

此时的打印结果为:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"BeiJing","custName":"Tom","id":1}],建议以后再使用 JSON 的 toJSONString() 方法时将第二个参数添加上

再深入一点,来看一个常见的问题,Department 和 Manager 类维护双向一对一的关联关系,Department 类中有 Manager 类的引用,Manager 类中有 Department 类的引用,来看如下代码:在 11 和 12 行设置了关联关系,14 行和 15 行进行 JSON 字符串的转换,结果会怎样呢?

  @Test public void test4() { Manager mgr = new Manager(); mgr.setMgrId(1); mgr.setMgrName("Tom");  Department dept = new Department(); dept.setDeptId(2); dept.setDeptName("DEV");  mgr.setDept(dept); dept.setManager(mgr);  String jsonStr = JSON.toJSONString(dept, SerializerFeature.DisableCircularReferenceDetect);// String jsonStr = JSON.toJSONString(mgr, SerializerFeature.DisableCircularReferenceDetect); System.out.println(jsonStr); }

答案是,抛出了异常,常见的 java.lang.StackOverflowError,抛异常的原因是双方都维护关联关系进入了死循环,那么如何解决这个问题呢?可以在一方添加 @JSONField(serialize=false) 注解,7 行所示,即可解决

public class Department {  private Integer deptId;  private String deptName;  @JSONField(serialize=false) private Manager manager; public Integer getDeptId() { return deptId; } public void setDeptId(Integer deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Manager getManager() { return manager; } public void setManager(Manager manager) { this.manager = manager; } }

打印结果为:{"dept":{"deptId":2,"deptName":"DEV"},"mgrId":1,"mgrName":"Tom"},结果也很令人满意。

最后提供一个 fastjson 的工具类,开发时可以直接使用,供大家参考

package qi.ssh.utils;import java.io.IOException;import java.util.Date;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletResponse;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;public class FastJsonUtil {   public static String toJSONString(Object object){ //DisableCircularReferenceDetect来禁止循环引用检测 return JSON.toJSONString(object,SerializerFeature.DisableCircularReferenceDetect); }  //输出json public static void write_json(HttpServletResponse response,String jsonString) { response.setContentType("application/json;utf-8"); response.setCharacterEncoding("UTF-8"); try {  response.getWriter().print(jsonString); } catch (IOException e) {  // TODO Auto-generated catch block  e.printStackTrace(); }  }  public static String ajaxResult(boolean success,String message) { Map map=new HashMap(); map.put("success", success);//是否成功 map.put("message", message);//文本消息 String json= JSON.toJSONString(map);  return json; }   public static String JsonFormatterAddPrefix(String json,String prefix,Map<String,Object> newmap) { if(newmap == null){  newmap = new HashMap(); } Map<String,Object> map = (Map) JSON.parse(json); for(String key:map.keySet()) {  Object object=map.get(key);  if(isEntity(object)){  String jsonString = JSON.toJSONString(object);  JsonFormatterAddPrefix(jsonString,prefix+key+".",newmap);    }else{  newmap.put(prefix+key, object);  }   } return JSON.toJSONString(newmap);  }  private static boolean isEntity(Object object) { if(object instanceof String ) {  return false; } if(object instanceof Integer ) {  return false; } if(object instanceof Long ) {  return false; } if(object instanceof java.math.BigDecimal ) {  return false; } if(object instanceof Date ) {  return false; } if(object instanceof java.util.Collection ) {  return false; } return true;  }}

二、Jackson

同样也需要导入 jar 包,Jackson 导入的 jar 包有三个

如何构建一个JSON字符串

具体使用也通过一个小例子说明:

package com.software.jackson;import java.util.Arrays;import java.util.List;import com.fasterxml.jackson.annotation.JsonIgnore;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.ObjectMapper;public class Customer { private int id; private String name; public Customer(int id, String name) {  super();  this.id = id;  this.name = name; } public int getId() {  return id; } public void setId(int id) {  this.id = id; } public String getName() {  return name; } public void setName(String name) {  this.name = name; }  public String getCity(){  return "BeiJing"; }  @JsonIgnore public String getSchool(){  return "School"; }  public static void main(String[] args) throws JsonProcessingException {  //创建ObjectMapper对象  ObjectMapper mapper = new ObjectMapper();    Customer customer = new Customer(1, "Tom");  List<Customer> lists = Arrays.asList(customer, new Customer(2, "Bob"));    //调用 ObjectMapper 的 writeValueAsString(xxx) 方法,把一个对象或几个传入,转为一个 JSON 字符串  String jsonStr = mapper.writeValueAsString(lists);  System.out.println(jsonStr);   }}

定义了一个 Customer 类,38 行和 43 行定义了两个额外的 get 方法并直接赋值,main 方法中创建 ObjectMapper 的对象,调用其 writeValueAsString() 方法,传入单个对象或对象的集合,便会返回对应的 JSON 字符串,打印结果为:[{"id":1,"name":"Tom","city":"BeiJing"},{"id":2,"name":"Bob","city":"BeiJing"}],大家可能会发现,我们 43 行定义的 getSchool() 方法中的 School 没有被打印出,这是因为我们在此方法上添加了 @JsonIgnore 注解,添加了此注解,在构造 JSON 字符串时便忽略此属性,细想一下 ,此注解添加到 get 方法上,这也说明 Jackson 构造 JSON 字符串时基于 getter 方法的。

与之前一样,我们想看一看 Jackson 有没有禁止循环的引用,类似的代码:

  @Test public void test2() throws JsonProcessingException {  List<Customer> lists = new ArrayList<>();  Customer customer = new Customer();  customer.setId(1);  customer.setCustName("Tom");  customer.setAddress("BeiJing");  lists.add(customer);  lists.add(customer);    ObjectMapper mapper = new ObjectMapper();  String jsonStr = mapper.writeValueAsString(lists);  System.out.println(jsonStr); }

来看一下输出结果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],结果显而易见。

我们再来看一看如果像 Fastjson 中测试的 Department 和 Manager 双向一对一映射的例子,Jackson 会表现的怎么样:

  @Test public void test1() throws JsonProcessingException {  Manager mgr = new Manager();  mgr.setMgrId(1);  mgr.setMgrName("Tom");    Department dept = new Department();  dept.setDeptId(2);  dept.setDeptName("DEV");    mgr.setDept(dept);  dept.setManager(mgr);    ObjectMapper mapper = new ObjectMapper();  String jsonStr = mapper.writeValueAsString(dept);  System.out.println(jsonStr); }

直接运行还是会出相同的异常 Caused by: java.lang.StackOverflowError,我们的思路与测试 Fastjson 一样,为 Department 中的 Manager 引用添加 @JsonIgnore 注解,异常解决了,但打印结果是很满意,结果为:{"deptId":2,"deptName":"DEV"} ,远不如 Fastjson 的输出结果。由此可以看出 Fastjson 功能之强大。

三、Google Gson

看看如何使用:jar 包呢只需要一个 gson-2.2.4.jar ,普通对象与集合转为 JSON 没有什么可说的,简单演示一下将 List 集合转为 JSON 字符串吧,直接 new 出 Gson 的对象,调用其 toJson() 方法传入需要转换的对象即可。

  @Test public void test2() {  List<Customer> lists = new ArrayList<>();  Customer customer = new Customer();  customer.setId(1);  customer.setCustName("Tom");  customer.setAddress("BeiJing");  lists.add(customer);  Customer customer2 = new Customer();  customer2.setId(1);  customer2.setCustName("Bob");  customer2.setAddress("ShangHai");  lists.add(customer2);  Gson gson = new Gson();  String jsonStr = gson.toJson(lists);  System.out.println(jsonStr); }

打印结果:[{"address":"BeiJing","custName":"Tom","id":1},{"address":"ShangHai","custName":"Bob","id":1}]

那有没有禁止循环引用呢?

  @Test public void test3() {  List<Customer> lists = new ArrayList<>();  Customer customer = new Customer();  customer.setId(1);  customer.setCustName("Tom");  customer.setAddress("BeiJing");  lists.add(customer);  lists.add(customer);    Gson gson = new Gson();  String jsonStr = gson.toJson(lists);  System.out.println(jsonStr); }

输出结果:[{"id":1,"custName":"Tom","address":"BeiJing"},{"id":1,"custName":"Tom","address":"BeiJing"}],显而易见是没有的。

若有双向一对一的关联关系映射的话,Google Gson 也是会有死循环问题造成 java.lang.StackOverflowError 异常,但是 Gson 并没有为我们提供一个注解,要解决此问题LZ提供一个解决方案的思路,Google Gson 使用的是 ExclusionStrategy 策略进行某个字段或某个域的序列化,可以通过此接口自定义一个 注解来解决此问题。但是建议大家如果涉及到双向关联关系的对象转换为 JSON 的需求是,使用 Fastjson。

四、三种方式的简单比较

LZ 从以下几个方面来比较构造 JSON 字符串的三种方式:

jar 包方面:显然是 Fastjson 和 Google Gson 胜出,Jackson 需要加入 3 个 jar 包。

简单对象或集合转为 JSON:若是普通的简单对象或集合进行转换,可能 Jackson 和 Google Gson 要胜出一些了,起码构造比较方便。

涉及到双向关联关系的转换:毫无疑问阿里巴巴的 Fastjson 将胜出。

建议大家在实际的开发中根据自己的需求合理选择某一方式。

以上就是如何构建一个JSON字符串,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯