Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson deserialize extra fields as Map

I'm looking to deserialize any unknown fields in a JSON object as entries in a Map which is a member of a POJO.

For example, here is the JSON:

{
  "knownField" : 5,
  "unknownField1" : "926f7c2f-1ae2-426b-9f36-4ba042334b68",
  "unknownField2" : "ed51e59d-a551-4cdc-be69-7d337162b691"
}

Here is the POJO:

class MyObject {
  int knownField;
  Map<String, UUID> unknownFields;
  // getters/setters whatever
}

Is there a way to configure this with Jackson? If not, is there an effective way to write a StdDeserializer to do it (assume the values in unknownFields can be a more complex but well known consistent type)?

like image 854
kag0 Avatar asked Aug 25 '16 23:08

kag0


People also ask

What is the difference between JsonProperty and JsonAlias?

@JsonProperty can change the visibility of logical property using its access element during serialization and deserialization of JSON. @JsonAlias defines one or more alternative names for a property to be accepted during deserialization.

How do you make a Map object serializable?

We are using writeObject() method of ObjectOutputStream to serialize HashMap in Java. In the following program, we save the hashmap content in a serialized newHashMap file. Once you run the following code, a newHashMap file will be created. This file is used for deserialization in the next upcoming program.

Does Jackson ignore unknown properties?

Jackson API provides two ways to ignore unknown fields, first at the class level using @JsonIgnoreProperties annotation and second at the ObjectMapper level using configure() method.

How does ObjectMapper readValue work?

The simple readValue API of the ObjectMapper is a good entry point. We can use it to parse or deserialize JSON content into a Java object. Also, on the writing side, we can use the writeValue API to serialize any Java object as JSON output.

How do I serialize a map in Jackson?

ObjectMapper is Jackson's serialization mapper. It allows us to serialize our map, and write it out as a pretty-printed JSON String using the toString () method in String: 3.2. Map<Object, String> Serialization With a few extra steps, we can also serialize a map containing a custom Java class.

How do I deserialize a map into a Java class?

There is another option when we deserialize into a Java class that contains a Map; we can use Jackson's KeyDeserializer class, one of the many Deserialization classes that Jackson offers. Let's annotate our ClassWithAMap with @JsonCreator, @JsonProperty, and @JsonDeserialize:

What is deserialization in Java?

Deserialization converts a stream of bytes into a Java object that we can use in code. In this section, we'll deserialize JSON input into Maps of different signatures. 4.1. Map<String, String> Deserialization

Why aren't the values in my serialized map being deserialized correctly?

The issue I'm running into is that since the values in the serialized map do not have any type information, they are not deserialized correctly. For example, in the sample above, enumValue1 should be deserialized as an enum value but is instead deserialized as a String.


1 Answers

There is a feature and an annotation exactly fitting this purpose.

I tested and it works with UUIDs like in your example:

class MyUUIDClass {
    public int knownField;

    Map<String, UUID> unknownFields = new HashMap<>();

    // Capture all other fields that Jackson do not match other members
    @JsonAnyGetter
    public Map<String, UUID> otherFields() {
        return unknownFields;
    }

    @JsonAnySetter
    public void setOtherField(String name, UUID value) {
        unknownFields.put(name, value);
    }
}

And it would work like this:

    MyUUIDClass deserialized = objectMapper.readValue("{" +
            "\"knownField\": 1," +
            "\"foo\": \"9cfc64e0-9fed-492e-a7a1-ed2350debd95\"" +
            "}", MyUUIDClass.class);

Also more common types like Strings work:

class MyClass {
    public int knownField;

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

    // Capture all other fields that Jackson do not match other members
    @JsonAnyGetter
    public Map<String, String> otherFields() {
        return unknownFields;
    }

    @JsonAnySetter
    public void setOtherField(String name, String value) {
        unknownFields.put(name, value);
    }
}

(I found this feature in this blog post first).

like image 128
Peter Lamberg Avatar answered Oct 08 '22 20:10

Peter Lamberg