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中的“:”,且业务中需要对其进行解析,后续的解析逻辑就会报错,所以各位可以根据实际的业务进行处理。