【问题标题】:How to convert a JSON string to a Map<String, String> with Jackson JSON如何使用 Jackson JSON 将 JSON 字符串转换为 Map<String, String>
【发布时间】:2011-02-01 06:35:22
【问题描述】:

我正在尝试做这样的事情,但它不起作用:

Map<String, String> propertyMap = new HashMap<String, String>();

propertyMap = JacksonUtils.fromJSON(properties, Map.class);

但是 IDE 说:

未经检查的分配Map to Map&lt;String,String&gt;

这样做的正确方法是什么? 我只使用 Jackson,因为这是项目中已经可用的,是否有本地 Java 方式来转换 JSON 或从 JSON 转换?

在 PHP 中,我只需 json_decode($str) 并返回一个数组。我在这里需要基本相同的东西。

【问题讨论】:

  • JacksonUtils 类从何而来?我在任何杰克逊版本中都没有看到它。
  • 它是我们对 Jackson 的包装器,处理一些你必须做的 JsonFactory 和 ObjectMapper 的事情。
  • 所以,问题在于 JacksonUtils.fromJSON() 没有声明返回 Map,而只是返回 Map。
  • 顺便说一句,不要在第一行分配新的 HashMap:这会被忽略。只是接听电话。
  • 标题与您描述的问题无关,与无类型集合有关。下面的答案是您真正想问的正确答案。

标签: java jackson


【解决方案1】:

[2020 年 9 月更新] 虽然我多年前的原始答案似乎很有帮助并且仍在获得支持,但我现在使用 Google 的 GSON 库,我发现它更直观。

我有以下代码:

public void testJackson() throws IOException {  
    ObjectMapper mapper = new ObjectMapper(); 
    File from = new File("albumnList.txt"); 
    TypeReference<HashMap<String,Object>> typeRef 
            = new TypeReference<HashMap<String,Object>>() {};

    HashMap<String,Object> o = mapper.readValue(from, typeRef); 
    System.out.println("Got " + o); 
}   

它正在从文件中读取,但mapper.readValue() 也将接受InputStream,您可以使用以下命令从字符串中获取InputStream

new ByteArrayInputStream(astring.getBytes("UTF-8")); 

my blog 上有更多关于映射器的解释。

【讨论】:

  • @Suraj,根据文档,我同意我无法从第一原理中推断出公式。这并不奇怪,因为它表明 Java 比我们想象的要复杂。
  • Krige:我认为很难让映射器运行起来,但我已经添加了关于如何将该技术应用于字符串的注释
  • 一个小注释:创建JsonFactory 的第一行不需要。 ObjectMapper可以自己自动创建。
  • @djna 发帖人要求提供Map&lt;String, String&gt;,而您提供了Map&lt;String, Object&gt;
  • 要将地图写成字符串,你可以这样做mapper.writeValueAsString(hashmap)
【解决方案2】:

试试TypeFactory。这是 Jackson JSON (2.8.4) 的代码。

Map<String, String> result;
ObjectMapper mapper;
TypeFactory factory;
MapType type;

factory = TypeFactory.defaultInstance();
type    = factory.constructMapType(HashMap.class, String.class, String.class);
mapper  = new ObjectMapper();
result  = mapper.readValue(data, type);

这是旧版 Jackson JSON 的代码。

Map<String, String> result = new ObjectMapper().readValue(
    data, TypeFactory.mapType(HashMap.class, String.class, String.class));

【讨论】:

  • TypeFactory.mapType(...) 现在已弃用,试试这个: new TypeReference>() {}
  • @cyber-monk 这消除了警告,但实际上并没有检查类型。
【解决方案3】:

您收到的警告是由编译器完成的,而不是由库(或实用程序方法)完成的。

直接使用 Jackson 的最简单方法是:

HashMap<String,Object> props;

// src is a File, InputStream, String or such
props = new ObjectMapper().readValue(src, new TypeReference<HashMap<String,Object>>() {});
// or:
props = (HashMap<String,Object>) new ObjectMapper().readValue(src, HashMap.class);
// or even just:
@SuppressWarnings("unchecked") // suppresses typed/untype mismatch warnings, which is harmless
props = new ObjectMapper().readValue(src, HashMap.class);

您调用的实用程序方法可能只是做类似的事情。

【讨论】:

  • OP 要求提供Map&lt;String, String&gt;,而您提供了Map&lt;String, Object&gt;
【解决方案4】:
ObjectReader reader = new ObjectMapper().readerFor(Map.class);

Map<String, String> map = reader.readValue("{\"foo\":\"val\"}");

注意reader 实例是线程安全的。

【讨论】:

  • @dpetruha OP 要求提供 Map&lt;String, String&gt;,而您提供了 Map&lt;String, Object&gt;
【解决方案5】:

从字符串转换为 JSON 映射:

Map<String,String> map = new HashMap<String,String>();

ObjectMapper mapper = new ObjectMapper();

map = mapper.readValue(string, HashMap.class);

【讨论】:

  • 以上结果仍然是Type safety: The expression of type HashMap needs unchecked conversion to conform to Map&lt;String,String&gt;。虽然这可以通过 @SuppressWarnings 注释来抑制,但我建议先使用 TypeReference 或按照 Staxman 的说明进行下一步
  • 要摆脱类型安全警告,您可以使用map = mapper.readValue(string, map.getClass()); - 假设您已经实例化了地图,就像这里的情况一样。
  • 如果var的类型是Map,只是获取对象类是不对的。
【解决方案6】:
JavaType javaType = objectMapper.getTypeFactory().constructParameterizedType(Map.class, Key.class, Value.class);
Map<Key, Value> map=objectMapper.readValue(jsonStr, javaType);

我认为这会解决你的问题。

【讨论】:

  • 在 java doc 中:@since 2.5 -- 但可能会在 2.7 或 2.8 中弃用(2.7 不需要)
【解决方案7】:

以下对我有用:

Map<String, String> propertyMap = getJsonAsMap(json);

getJsonAsMap 的定义如下:

public HashMap<String, String> getJsonAsMap(String json)
{
    try
    {
        ObjectMapper mapper = new ObjectMapper();
        TypeReference<Map<String,String>> typeRef = new TypeReference<Map<String,String>>() {};
        HashMap<String, String> result = mapper.readValue(json, typeRef);

        return result;
    }
    catch (Exception e)
    {
        throw new RuntimeException("Couldnt parse json:" + json, e);
    }
}

请注意,如果您的 json 中有子对象(因为它们不是 String,它们是另一个 HashMap),这失败,但如果您的 json 是如下属性的键值列表:

{
    "client_id": "my super id",
    "exp": 1481918304,
    "iat": "1450382274",
    "url": "http://www.example.com"
}

【讨论】:

    【解决方案8】:

    只是想给出一个 Kotlin 的答案

    val propertyMap = objectMapper.readValue<Map<String,String>>(properties, object : TypeReference<Map<String, String>>() {})
    

    【讨论】:

    • 嗯,不知道为什么这被否决了。这条线不仅对我有用,它还提供了正确方法的关键。通过将 Map 替换为不同的所需类型,映射器会将字符串转换为任何复杂的集合,例如 List 或 List>
    • 谢谢,我正在寻找 Kotlin 的答案。
    【解决方案9】:

    使用 Google 的 Gson

    为什么不使用here 中提到的 Google 的 Gson?

    非常直截了当,为我完成了这项工作:

    HashMap<String,String> map = new Gson().fromJson( yourJsonString, new TypeToken<HashMap<String, String>>(){}.getType());
    

    【讨论】:

    • 同意,世界已经在前进,Gson 使用起来要容易得多。
    【解决方案10】:

    这里是这个问题的通用解决方案。

    public static <K extends Object, V extends Object> Map<K, V> getJsonAsMap(String json, K key, V value) {
        try {
          ObjectMapper mapper = new ObjectMapper();
          TypeReference<Map<K, V>> typeRef = new TypeReference<Map<K, V>>() {
          };
          return mapper.readValue(json, typeRef);
        } catch (Exception e) {
          throw new RuntimeException("Couldnt parse json:" + json, e);
        }
      }
    

    希望有一天有人会考虑创建一个实用方法来转换为任何键/值类型的 Map 因此这个答案:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-14
      • 2019-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-26
      相关资源
      最近更新 更多