You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:45:31