Java使用Jackson ObjectMapper转JSON字符串为HashMap报错如何解决?
问题描述
尝试使用com.fasterxml.jackson.databind.ObjectMapper实现JSON字符串到HashMap的转换,初始实现代码如下:
String str = "{\"key\":\"[{\"one\":\"value\"}]\"}"; ObjectMapper mapper = new ObjectMapper(); try { HashMap<String, String> map = mapper.readValue(str, HashMap.class); System.out.println(map); } catch (JsonMappingException e) { e.printStackTrace(); } catch (JsonProcessingException e) { e.printStackTrace(); }
运行代码抛出如下异常:
com.fasterxml.jackson.core.JsonParseException: Unexpected character ('o' (code 111)): was expecting comma to separate Object entries at [Source: (String)"{"key": "[{"one":"value"}]"}";;; line: 1, column: 14] at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:2391) at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:735) at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:659) at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._skipComma(ReaderBasedJsonParser.java:2382) at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextFieldName(ReaderBasedJsonParser.java:947) at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringKeyMap(MapDeserializer.java:594) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:437) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:32) at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597) at com.sample.quick.check.one.App.main(App.java:15)
需求:将JSON字符串中的键和值都作为字符串类型存入HashMap,不需要将值解析为JSONArray。
问题根因
- 传入的JSON字符串本身语法不合法:Java代码中转义不完整,最终生成的实际JSON内容里,
key对应值的内部双引号没有转义,解析器读到one的首字符o时,判定上一个字符串值已经结束,后续应该出现逗号分隔键值对,因此抛出解析错误。 - 即使修正JSON格式,直接用
HashMap.class反序列化也不符合需求:Jackson默认会自动识别值的JSON结构,将符合数组、对象格式的内容解析为对应Java类型,不会保留原始字符串形态。
实现方案
两种方案都可以实现所有值以原始字符串形式存入Map,注意首先要把JSON字符串的转义写对,合法的JSON字符串中,值内部的双引号必须转义,对应Java代码里要写两层反斜杠。
方案1:读取为JsonNode后手动转字符串
不需要额外自定义组件,直接把JSON读为Jackson的树结构节点,遍历节点时把值直接转成字符串存入Map即可:
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class JsonParseDemo { public static void main(String[] args) throws JsonProcessingException { // 修正转义后的合法JSON字符串 String validJsonStr = "{\"key\":\"[{\\\"one\\\":\\\"value\\\"}]\"}"; ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(validJsonStr); HashMap<String, String> resultMap = new HashMap<>(); Iterator<Map.Entry<String, JsonNode>> fieldIterator = rootNode.fields(); while (fieldIterator.hasNext()) { Map.Entry<String, JsonNode> entry = fieldIterator.next(); // 直接取值的文本内容,不做结构化解析 resultMap.put(entry.getKey(), entry.getValue().asText()); } System.out.println(resultMap); // 输出结果:{key=[{"one":"value"}]} } }
方案2:自定义Map反序列化器
如果需要全局复用这个逻辑,可以自定义反序列化器,解析Map时直接把值读取为原始字符串,跳过结构化解析步骤:
import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import java.io.IOException; import java.util.HashMap; public class CustomDeserializerDemo { static class RawStringMapDeserializer extends StdDeserializer<HashMap<String, String>> { public RawStringMapDeserializer() { super(HashMap.class); } @Override public HashMap<String, String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { HashMap<String, String> map = new HashMap<>(); if (p.currentToken() != JsonToken.START_OBJECT) { ctxt.reportWrongTokenException(this, JsonToken.START_OBJECT, "Expected start of JSON object"); } while (p.nextToken() != JsonToken.END_OBJECT) { String key = p.currentName(); p.nextToken(); // 直接读取值为原始字符串,不解析内部JSON结构 String value = p.getValueAsString(); map.put(key, value); } return map; } } public static void main(String[] args) throws JsonProcessingException { String validJsonStr = "{\"key\":\"[{\\\"one\\\":\\\"value\\\"}]\"}"; ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(HashMap.class, new RawStringMapDeserializer()); mapper.registerModule(module); HashMap<String, String> resultMap = mapper.readValue(validJsonStr, HashMap.class); System.out.println(resultMap); // 输出结果:{key=[{"one":"value"}]} } }
内容的提问来源于stack exchange,提问作者Ramachandran Rajasekaran
相关产品推荐
相关产品推荐

