Deserializing into a Hashmap of Custom Objects with Jackson

Deserializing into a HashMap of custom objects with jackson

You should create specific Map type and provide it into deserialization process:

TypeFactory typeFactory = mapper.getTypeFactory();
MapType mapType = typeFactory.constructMapType(HashMap.class, String.class, Theme.class);
HashMap<String, Theme> map = mapper.readValue(json, mapType);

Deserialize a JSON array partially into a HashMap with the help of jackson

Maybe you have missed with adding module.addDeserializer

HashMapValueDeserializer.class

public class HashMapValueDeserializer extends JsonDeserializer<HashMap<String, String>> {
@Override
public HashMap<String, String> deserialize(JsonParser parser, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
HashMap<String, String> ret = new HashMap<String, String>();

ObjectCodec codec = parser.getCodec();
TreeNode node = codec.readTree(parser);

for (JsonNode n : (ArrayNode)node){
JsonNode c = n.get("c");
JsonNode b = n.get("b");
ret.put(c.asText(), b.asText());
}
return ret;
}
}

Test.class

public class Test {
public static void main(String[] args) throws FileNotFoundException, MalformedURLException, JsonProcessingException {
String jsonArray = "[{ \"a\" : \"1\", \"b\" : \"2\", \"c\" : \"one\", \"d\" : \"3\" }, { \"a\" : \"4\", \"b\" : \"5\", \"c\" : \"two\", \"d\" : \"6\" }, { \"a\" : \"7\", \"b\" : \"8\", \"c\" : \"three\", \"d\" : \"9\" }]";

ObjectMapper mapper = new ObjectMapper();

SimpleModule module =
new SimpleModule("HashMapValueDeserializer", new Version(1, 0, 0, null, null, null));
module.addDeserializer(HashMap.class, new HashMapValueDeserializer());
mapper.registerModule(module);

HashMap<String, Integer> result = mapper.readValue(jsonArray, HashMap.class);
System.out.println(result);
}

}

Output :

{one=2, two=5, three=8}

I need to deserialize a JSON array to a HashMap with jackson

Just read it as a List of Map instances and collect it to a new Map after deserialisation process:

List<Map<String, Object>> listOfMaps = mapper.readValue(json, new TypeReference<List<Map<String, Object>>>() {});
Map<String, Object> desiredMap = listOfMaps.stream().collect(HashMap::new,
(result, map) -> result.put(map.get("name").toString(), map.get("values")),
(existing, replacement) -> { });

How to Deserialize a MapString,Object correctly in Jackson

The solution that worked for me was using custom deserialization, @JsonDeserialize annotation & JsonDeserializer interface, in order to achieve the desired results.

Below is the solution:

public class Request {

private String method;
private String resource;
@JsonDeserialize(using = BodyDeserializer.class)
private final Map<String, Object> body;
private final Map<String, String> headers;
private final Map<String, String[]> parameters;

public Request() {
this.body = new HashMap();
this.headers = new HashMap();
this.parameters = new HashMap();
}

public String getMethod() {
return method;
}

public String getResource() {
return resource;
}

public Map<String, Object> getBody() {
return body;
}

public Map<String, String> getHeaders() {
return headers;
}

public Map<String, String[]> getParameters() {
return parameters;
}

public String getHeader(String name) {
return headers.get(name);
}

public Request setBody(Map<String, Object> body) {
this.body.putAll(body);
return this;
}

public Request setMethod(String name) {
this.method = name;
return this;
}

public Request setResource(String name) {
this.resource = name;
return this;
}

public Request setHeaders(Map<String, String> headers) {
this.headers.putAll(headers);
return this;
}

public Request setParameters(Map<String, String[]> parameters) {
this.parameters.putAll(parameters);
return this;
}

private static class BodyDeserializer extends JsonDeserializer<Map<String, Object>> {

@Override
public Map<String, Object> deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
JsonDeserializer<Object> deserializer = dc.findRootValueDeserializer(dc.constructType(Map.class));
Map<String, Object> map = (Map<String, Object>) deserializer.deserialize(jp, dc);
return map;
}
}
}

Java/Jackson: Deserialize JSON into class with HashMap

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

Jackson - deserializing Map implementation as HashMap

Ok, i found how to do this with custom serializer (the trick was to tell serializer to use java.util.HashMap instead of the real class name):

public class MessageHeadersJsonSerializer extends JsonSerializer<MessageHeaders>{
@Override
public void serializeWithType(MessageHeaders value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
typeSer.writeTypePrefixForObject(value, gen, HashMap.class);
serialize(value, gen, serializers);
typeSer.writeTypeSuffixForObject(value, gen);
}

@Override
public void serialize(MessageHeaders value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
for(Map.Entry<String, Object> entry : value.entrySet()){
gen.writeFieldName(entry.getKey());
gen.writeObject(entry.getValue());
}
}
}

And then just registered it as a MixIn:

@JsonSerialize(using = MessageHeadersJsonSerializer.class)
public abstract class MessageHeadersMixIn {}

And on parent object I'm deserializing it as HashMap:

public abstract class GenericMessageMixIn<T> {
@JsonCreator
public GenericMessageMixIn(
@JsonProperty("payload") T payload,
@JsonProperty("headers") Map<String, Object> headers
){}
}

And finally all works OK!

Jackson searches method on wrong level on deserialization

I found my problem.
I formerly mapped my concrete implementation of the interface AuthorizationRequest via a handler:

        mapper.addHandler(new DeserializationProblemHandler() {
@Override
public Object handleMissingInstantiator(DeserializationContext ctxt, Class<?> instClass, ValueInstantiator valueInsta, JsonParser p, String msg) throws IOException {
if(instClass.isAssignableFrom(AuthorizationRequest.class)) {
return new DeserializedAuthorizationRequest();
}
return super.handleMissingInstantiator(ctxt, instClass, valueInsta, p, msg);
}
});

This seems to be definitely not the same as annotating the field with the concrete class. This now works without problems:

public class DeserializedOAuth2Authentication extends OAuth2Authentication{

...

@Override
@JsonProperty("authorizationRequest")
@JsonDeserialize(as = DeserializedAuthorizationRequest.class)
public AuthorizationRequest getAuthorizationRequest() {
return authorizationRequest;
}

public void setAuthorizationRequest(AuthorizationRequest authorizationRequest) {
this.authorizationRequest = authorizationRequest;
}

}

Serialization and deserialization of HashMapMyObject, ListInteger with Jackson

Your problem is that Jackson has a standard for converting a Map to JSON. The keys of the map are used as the property names in the results JSON.

Map<String, Double> groceryPrices = new HashMap<>();
groceryPrices.put("apple", 0.25);
groceryPrices.put("orange", 0.30);

This naturally translates to a JSON object:

{
"apple": 0.25,
"orange": 0.30
}

The problem is you are using a complex object to represent a key. There is no simple method for serializing and deserializing your complex object to/from a String.

If you don't want to write custom serialization, I suggest you change your data structure. Your current structure ties together a model with it's Integers. You could fold the list of Integers into the Model object itself:

Map<String, Model> models; // This could map modelId -> Model which now contains the integers

Jackson JSON object mapper deserializes to LinkedHashMap instead of HashMap

If you want some other type, you can implement the Jackson converter and annotate your class with it.

public static class TransformConverter implements Converter<Map<String,List>,Map<String,List>>{

@Override
public Map<String,List> convert(Map<String,List> map) {
return new HashMap<>(map);
}

@Override
public JavaType getInputType(TypeFactory typeFactory) {
return typeFactory.constructMapType(Map.class, String.class, List.class);
}

@Override
public JavaType getOutputType(TypeFactory typeFactory) {
return typeFactory.constructMapType(Map.class, String.class, List.class);
}
}

public static class Transformer {
@JsonDeserialize(converter = TransformConverter.class)
Map<String, List<Transform>> transforms;
//rest of your class
}


Related Topics



Leave a reply



Submit