在介紹異常之前,先貼出寫的工具類吧,畢竟空談無用嘛。
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中的“:”,且業務中需要對其進行解析,后續的解析邏輯就會報錯,所以各位可以根據實際的業務進行處理。