Deserializing JSON map with "key" & "value" properties does not work with Jackson
12,193
If we will convert Map
to json:
Map<String, String> map = new HashMap<String, String>();
map.put("operating system", "GNU/Linux");
map.put("allergies", "weed");
The output will be:
{"operating system":"GNU/Linux","allergies":"weed"}
As we can see there is no key/value
.
Solution
WrapperObject
@JsonIgnoreProperties(ignoreUnknown = true)
public class WrapperObject { // we can give any name to class, its only external {}
private Attributes attributes;
public WrapperObject() {}
public Attributes getAttributes() {
return attributes;
}
}
Attributes
@JsonIgnoreProperties(ignoreUnknown = true)
public class Attributes {
public Attributes() {}
private ArrayList<Entry> entry;
public ArrayList<Entry> getEntry() {
return entry;
}
}
Entry
@JsonIgnoreProperties(ignoreUnknown = true)
public class Entry {
private String key;
private String value;
public Entry() {}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
}
Launcher
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String str = "{" +
" \"attributes\": {" +
" \"entry\": [" +
" {" +
" \"key\": \"operating system\"," +
" \"value\": \"GNU/Linux\"" +
" }," +
" {" +
" \"key\": \"allergies\"," +
" \"value\": \"weed\"" +
" }" +
" ]" +
" }" +
"}";
ObjectMapper mapper = new ObjectMapper();
WrapperObject mj = mapper.readValue(str, WrapperObject.class);
if(mj == null){
System.err.println("null");
}
// dummy check
System.out.println(mj.getAttributes().getEntry().get(0).getKey());
}
Output:
operating system
Related videos on Youtube
Author by
joelpet
Updated on September 15, 2022Comments
-
joelpet about 1 year
Questions
- To begin with, does the serialized JSON serialization below make sense?
- If so, why am I not getting the Map back?
- What can I do about it on the deserializing side?
JSON serialization of Map<String, String> property (excerpt):
{ "attributes": { "entry": [ { "key": "operating system", "value": "GNU/Linux" }, { "key": "allergies", "value": "weed" } ] } }
POJO for deserialization:
class Contact implements Comparable<Contact>, Serializable { @JsonProperty("attributes") private Map<String, String> attributes; ... }
Causes this exception:
Thread-4889 An exception occurred during request network execution :Could not read JSON: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: libcore.net.http.FixedLengthInputStream@43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: libcore.net.http.FixedLengthInputStream@43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]) org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: libcore.net.http.FixedLengthInputStream@43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: libcore.net.http.FixedLengthInputStream@43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]) at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readInternal(MappingJackson2HttpMessageConverter.java:126) at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:147) at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:76) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:484) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439) at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237) at com.example.providers.Query$1.loadDataFromNetwork(Query.java:99) at com.octo.android.robospice.request.CachedSpiceRequest.loadDataFromNetwork(CachedSpiceRequest.java:45) at com.octo.android.robospice.request.RequestRunner.processRequest(RequestRunner.java:130) at com.octo.android.robospice.request.RequestRunner$1.run(RequestRunner.java:197) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:390) at java.util.concurrent.FutureTask.run(FutureTask.java:234) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) at java.lang.Thread.run(Thread.java:841) Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_ARRAY token at [Source: libcore.net.http.FixedLengthInputStream@43822760; line: 1, column: 17] (through reference chain: com.example.model.Contact["attributes"]) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:691) at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:46) at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize(StringDeserializer.java:11) at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:430) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:312) at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26) at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:525) at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:106) at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:242) at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:118) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:227) at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.des
The attributes Object when inspected in debugger after deserialization:
Further inspection after changing to:
@JsonProperty("attributes") private Map<String, List<Map<String, String>>> attributes;
Dependencies:
- com.fasterxml.jackson.core:jackson-core:2.3.0
- com.fasterxml.jackson.core:jackson-databind:2.3.0
- com.fasterxml.jackson.core:jackson-annotations:2.3.0