【问题标题】:Java/Jackson: Deserialize JSON into class with HashMapJava/Jackson:使用 HashMap 将 JSON 反序列化为类
【发布时间】:2018-09-05 17:15:46
【问题描述】:

我想反序列化以下 JSON 输入:

{
  "key1": "value1",
  "key2": "value2"
}

放入包含哈希映射的类对象中:

public class ClassContainingMap {

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

  public Map<String, String> getMap() {
     return map;
  }

  public void setMap(Map<String, String> map) {
     this.map = map;
  }
}

执行时

ClassContainingMap m = objectMapper.readValue(json, ClassContaininMap.class);

我明白了

com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of test.ClassContainingMap: no Stri
ng-argument constructor/factory method to deserialize from String value ('key1')
 at [Source: "key1": "value1", "key2": "value2"; line: 1, column: 1]
    at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:270)
    at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:1456)
    at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1012)
    at com.fasterxml.jackson.databind.deser.ValueInstantiator._createFromStringFallbacks(ValueInstantiator.java:370)
    at com.fasterxml.jackson.databind.deser.std.StdValueInstantiator.createFromString(StdValueInstantiator.java:315)
    at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1283)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:159)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:150)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2858)

我发现当用@JsonValue 注释getter 时,我可以让另一个方向(序列化)工作,但到目前为止我还无法为反序列化解决这个问题。有没有什么简单的(注解?)方法可以实现这一点,而无需编写自定义反序列化器?

【问题讨论】:

    标签: java json hashmap jackson deserialization


    【解决方案1】:

    您没有提供如何使用 @JsonValue 注释的示例,所以我可能错过了一些东西,但无论如何。

    在序列化时,我认为您会执行以下操作:

    ClassContainingMap ccm = new ClassContainingMap();
    ccm.getMap().put("key1", "value1");
    ccm.getMap().put("key2", "value2");
    
    System.out.println(om.writeValueAsString(ccm)); 
    

    这将起作用并将生成以下 JSON:

    {
        "map": {
            "key1":"value1",
            "key2":"value2",
        }
    }
    

    但这不等于你要读取的JSON结构ClassContainingMap

    {
        "key1": "value1",
        "key2": "value2"
    }
    

    即前者是来自ClassContainingMap 的数据,而后者是“仅”Map 我认为您想填充到ClassContainingMap 中的数据。

    你有两个选项可以检查,你可以;

    1. 使用正确的 JSON 结构作为对应 ClassContainingMap 的源
    2. 只需将其反序列化为一个简单的地图,例如:

      Map map = om.readValue(i, Map.class);
      
    3. 如果以上任何一种都可行,一种方法是使用@JsonCreator

      @JsonCreator(mode=Mode.DELEGATING)
      public ClassContainingMap(@JsonProperty("map")Map<String,String> map) {
          this.map = map;
      }
      
      @JsonValue
      public Map<String, String> getMap() {
          return map;
      }
      

    查看更多关于 3rd 的信息,例如 here

    【讨论】:

    • 关于序列化-如果我用@JsonValue 注释public Map&lt;String, String&gt; getMap(),那么它会被序列化为所需的JSON 结构。关于1 - 不幸的是不可能,因为它是作为 POST 有效负载的 JSON,以及 2 - 是的,这就是我可能最终要做的事情。没什么大不了的,只是想看看是否有任何注释可以实现反序列化的等效项(我知道这是非常具体的用例,因为该类只有一个 map 成员)。无论如何,谢谢!
    • @dflachbart 稍微更新了答案。这是一个品味问题 - 我认为 - 如果第 3 次比第 2 次更方便。
    • 也许你可以使用@JsonUnwrapped
    • @FedericoPeraltaSchaffner 是的,我试过了,但它似乎在 Map 上不起作用
    • @pirho 太好了,感谢您指出JsonCreator,这行得通!
    猜你喜欢
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 2020-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多