首页 > 技术文章 > 【Java】JSON踩坑01 -- 字符串多出前后双引号和转义符

yb-ken 2022-01-18 17:27 原文

场景:

  调用后台接口后返回这么一串数据,不知道是在哪里又作了一次转义,现在得到的字符串格式是:

"\"{\\\"A\\\":\\\"a\\\",\\\"B\\\":\\\"b\\\"}\"" 

   也就是说,前后多了两个双引号,中间的转义字符也被转义了。

   用System.out.println()打印出来就是 

"{\"A\":\"a\",\"B\":\"b\"}"

 

关于JSON反序列化的坑(JAVA)

RestTemplate的getForObject()

public void test() {
 // 使用方法一,不带参数
 String url = "https:/://xxx/xx/x?id=666106231640";
Data data = restTemplate.getForObject(url, InnerRes.class);
 System.out.println(data);

 // 使用方法二,map传参
 url = "https://://xxx/xx/x?id={id}";
 Map<String, Object> params = new HashMap<>();
 params.put("id", 123);
Data = restTemplate.getForObject(url, Data.class, params);
 System.out.println(data);

 

这个方法在大多数情况下都没问题,还有postForObject()等好用的方法可以用

但是如果返回的值很奇怪,不是严格的JSON,那会报错了,比如遇到一个返回的JSON,内部嵌套的内容有的在大括号外还多了双引号,有的没有,比如:

{
    "result":"{"name":"mike","addr":"beijing"}",
    "code":"200",
    "error":""
}

 

也不懂对面接口为什么要这么做,也可能是本人见得比较少,不过也没办法了,只能当字符串来处理了

先使用

String str = restTemplate.getForObject(url, String.class);

然后处理字符串,先替换掉转义的""和大括号两边的双引号,假设取到下面这串str

str= "{\"result\":\"{\"name\":\"mike\",\"addr\":\"beijing\"}\",\"code\":\"200\",\"error\":\"\"}";
str = str.replace("\\","");
str = str.replace("\"{","{");
str = str.replace("}\"","}");

 然后使用ObjectMapper的readValue()转化为对象

// 创建ObjectMapper
ObjectMapper mapper = new ObjectMapper();
// 下面这步的作用就是忽略json中存在,但java中的目标类中不存在的字段,否则会反序列化报错
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
MyObj obj = mapper.readValue(str,MyObj);

 

如果MyObj嵌套多个内部类的话,不能够越级访问,如:

    @Getter
    @Setter
    @ToString
    @AllArgsConstructor
    @NoArgsConstructor
    public static class test{
        private String one;
        private String two;
        private Mytest mytest;
        @Getter
        @Setter
        @ToString
        @AllArgsConstructor
        @NoArgsConstructor
        public static class Mytest{
        	private String mytest1;
        	private String mytest2;
        }  
    }

 

JSON中存在

{
   "one": "valone",
   "two": "valtwo",
   "mytest": {
   	"mytest1": "t1",
   	"mytest2": "t2"
   }
}

 

想要获取mytest1的内容,就要创建一个Mytest的内部类,然后才会匹配

最好要把里面各个字段都设为public static,如果是private的话,mapper.readValue()返回的对应字段是null,具体原因未知…
猜想,可能是与ObjectMapper的反射机制有关,private就访问不到了,但是后来发现我有一个三层的内部类,外面两层用private的字段是可以获取到的,第三层后就是null了,

必须改成public才能获取到
我使用了lombok,不知道会不会于此有关,希望有知道原因的大佬希望能指点

 

推荐阅读