Fork me on GitHub

Jackson工具类解析异常--Illegal unquoted character ((CTRL-CHAR, code 26))

在介绍异常之前,先贴出写的工具类吧,毕竟空谈无用嘛。
public class JacksonUtil {
   private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);

    private final static ObjectMapper OBJ_MAPPER = new ObjectMapper();
    public static ObjectMapper getInstance() {
        return OBJ_MAPPER;
    }

    /**
     * bean、array、List、Map --> json
     * 
     * @param obj
     * @return json string
     * @throws Exception
     */
    public static String writeValueAsString(Object obj) {
       try {
         return getInstance().writeValueAsString(obj);
      } catch (JsonGenerationException e) {
         logger.error(e.getMessage(), e);
      } catch (JsonMappingException e) {
         logger.error(e.getMessage(), e);
      } catch (IOException e) {
         logger.error(e.getMessage(), e);
      }
        return null;
    }

    /**
     * string --> bean、Map、List(array)
     * 
     * @param jsonStr
     * @param clazz
     * @return obj
     * @throws Exception
     */
    public static <T> T readValue(String jsonStr, Class<T> clazz) {
       try {
         return getInstance().readValue(jsonStr, clazz);
      } catch (JsonParseException e) {
         logger.error(e.getMessage(), e);
      } catch (JsonMappingException e) {
         logger.error(e.getMessage(), e);
      } catch (IOException e) {
         logger.error(e.getMessage(), e);
      }
       return null;
    }

   /**
    * string --> List<Bean>...
    *
    * @param jsonStr
    * @param parametrized
    * @param parameterClasses
    * @param <T>
    * @return
    */
   public static <T> T readValue(String jsonStr, Class<?> parametrized, Class<?>... parameterClasses) {
      try {
         JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
         return getInstance().readValue(jsonStr, javaType);
      } catch (JsonParseException e) {
         logger.error(e.getMessage(), e);
      } catch (JsonMappingException e) {
         logger.error(e.getMessage(), e);
      } catch (IOException e) {
         logger.error(e.getMessage(), e);
      }
      return null;
   }
}

大家可以先看下工具类代码,如果有问题,欢迎沟通交流。有同学会问为什么不用Gson,完全不用考虑这些问题,提前说明下,项目组不让用,至于原因,自行Google...

之前解析一直都没有问题的,直到有一天程序运行报错,待解析的jsonStr及报错如下

    public static void main(String[] args) {
        String jsonStrErr = "[{\"logId\":1114,\"logDateTim\":1650362257000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}},{\"logId\":1115,\"logDateTim\":1650362258000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}},{\"logId\":1099,\"logDateTim\":1650362242000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}}][{\"logId\":1114,\"logDateTim\":1650362257000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}},{\"logId\":1115,\"logDateTim\":1650362258000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}},{\"logId\":1099,\"logDateTim\":1650362242000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}}]";
        System.out.println(JSONObject.toJSONString(readValue(jsonStrErr, List.class, HandleCallbackParam.class)));
    }
15:15:13.305 admin [main] ERROR c.w.d.a.c.u.JacksonUtil - Illegal unquoted character ((CTRL-CHAR, code 26)): has to be escaped using backslash to be included in string value
 at [Source: (String)"[{"logId":1114,"logDateTim":1650362257000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1115,"logDateTim":1650362258000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1099,"logDateTim":1650362242000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}}][{"logId":1114,"logDateTim":1650362257000,"execut"[truncated 402 chars]; line: 1, column: 77] (through reference chain: java.util.ArrayList[0]->com.wugui.datatx.core.biz.model.HandleCallbackParam["executeResult"]->com.wugui.datatx.core.biz.model.ReturnT["msg"])
com.fasterxml.jackson.databind.JsonMappingException: Illegal unquoted character ((CTRL-CHAR, code 26)): has to be escaped using backslash to be included in string value
 at [Source: (String)"[{"logId":1114,"logDateTim":1650362257000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1115,"logDateTim":1650362258000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1099,"logDateTim":1650362242000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}}][{"logId":1114,"logDateTim":1650362257000,"execut"[truncated 402 chars]; line: 1, column: 77] (through reference chain: java.util.ArrayList[0]->com.wugui.datatx.core.biz.model.HandleCallbackParam["executeResult"]->com.wugui.datatx.core.biz.model.ReturnT["msg"])
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:394)
    at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:353)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.wrapAndThrow(BeanDeserializerBase.java:1711)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:290)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
    at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3042)
    at com.wugui.datax.admin.core.util.JacksonUtil.readValue(JacksonUtil.java:86)
    at com.wugui.datax.admin.core.util.JacksonUtil.main(JacksonUtil.java:99)
Caused by: com.fasterxml.jackson.core.JsonParseException: Illegal unquoted character ((CTRL-CHAR, code 26)): has to be escaped using backslash to be included in string value
 at [Source: (String)"[{"logId":1114,"logDateTim":1650362257000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1115,"logDateTim":1650362258000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}},{"logId":1099,"logDateTim":1650362242000,"executeResult":{"code":500,"msg":"block strategy effectCover Early [job running, killed]","content":null}}][{"logId":1114,"logDateTim":1650362257000,"execut"[truncated 402 chars]; line: 1, column: 100]
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:693)
    at com.fasterxml.jackson.core.base.ParserMinimalBase._throwUnquotedSpace(ParserMinimalBase.java:657)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString2(ReaderBasedJsonParser.java:2053)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString(ReaderBasedJsonParser.java:2024)
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText(ReaderBasedJsonParser.java:278)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:35)
    at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:10)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:288)
    ... 11 common frames omitted

错误内容如标题所示:“Illegal unquoted character ((CTRL-CHAR, code 26))”,意思很明显--非法无引号字符,也就是说jsonStr内部有非法字符集,可这块内容是接口回调返回的,网上有人说是因为不是标准的utf8格式导致的,controler设置一下就可以,但无法解决问题。

想了一下最简单的方案就是在使用工具类时将非法符号转换一下,将字符转换成““或者和其它格式,仔细查询jsonStr,发现非法的字符应该是“:”,于是很自然就想到最简单地处理方案

    public static void main(String[] args) {
        String jsonStrErr = "[{\"logId\":1114,\"logDateTim\":1650362257000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}},{\"logId\":1115,\"logDateTim\":1650362258000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}},{\"logId\":1099,\"logDateTim\":1650362242000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect\u001ACover Early [job running, killed]\",\"content\":null}}][{\"logId\":1114,\"logDateTim\":1650362257000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}},{\"logId\":1115,\"logDateTim\":1650362258000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}},{\"logId\":1099,\"logDateTim\":1650362242000,\"executeResult\":{\"code\":500,\"msg\":\"block strategy effect:Cover Early [job running, killed]\",\"content\":null}}]";
        System.out.println(JSONObject.toJSONString(readValue(jsonStrErr.replace( new String(Character.toChars(26) ),":"), List.class, HandleCallbackParam.class)));
    }

如上所写,将jsonStr内非法字符进行转换,语法很简单

str.replace( new String(Character.toChars(x) ),"")

这里面的X就是错误里面的(CTRL-CHAR, code 26)对应的code 值,我这里就是26,可以根据实际情况进行修改。简单的处理一下后,工具类运行正常,且能正确的奖str装换成对象。

但是觉得这种方案过于死板,无法涵盖处理各种可能存在的错误字符,于是在跟回调方确认改非法字符与业务无关后,又想到另一个方案

private final static ObjectMapper OBJ_MAPPER = new ObjectMapper();
    public static ObjectMapper getInstance() {
        OBJ_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
        return OBJ_MAPPER;
    }

意思就很明显了,就是对objectMapper进行配置,允许非法字符。这种方案处理就更方便了,但是仍旧存在问题,比如如特殊字符为key-value中的“:”,且业务中需要对其进行解析,后续的解析逻辑就会报错,所以各位可以根据实际的业务进行处理。

posted @ 2022-04-20 15:36  JackpotHan  阅读(4208)  评论(0编辑  收藏  举报