简体   繁体   中英

Java/Jackson: Deserialize JSON into class with HashMap

I want to deserialize the following JSON input:

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

into a class object containing a hash map:

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;
  }
}

When executing

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

I get

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)

I found that I can get the other direction (serialization) working when annotating the getter with @JsonValue , but so far I haven't been able to figure this out for deserialization. Is there any simple (annotation?) way to achieve this, without having to write a custom deserializer?

You did not provide an example how you use the @JsonValue annotation so I might have missed something, but anyway.

When serializing I think you do something like:

ClassContainingMap ccm = new ClassContainingMap();
ccm.getMap().put("key1", "value1");
ccm.getMap().put("key2", "value2");

System.out.println(om.writeValueAsString(ccm)); 

This will work and will produce the following JSON:

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

But this does not equal to the JSON structure you want to read to ClassContainingMap :

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

Namely the former is data from ClassContainingMap and the latter is "only" Map that I think you want to populate inside ClassContainingMap .

You have two options to check, you can;

  1. use the correct JSON structure as a source that corresponds ClassContainingMap
  2. just deserialize this to a simple map, like:

     Map map = om.readValue(i, Map.class); 
  3. and if either of above are possible, one way is to do it with @JsonCreator

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

See some more information about 3rd for example here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM