2

I'm using fasterXML's Jackson (v2.3.3) library to deserialize and serialize a custom class. The class is defined as following:

public class Person {

  private String name;
  private Map<String, Person> children;

  // lots of other fields of different types with no issues
}

the keys of map children are the name fields. I receive data in JSON with each person object structured as following (I have omitted the other fields):

{"name":"Bob", "children":[{"name":"Jimmmy"},{"name":"Judy"}]}

(Many Fields such as children are optional and aren't serialized when null)

I have been storing children in a List<Person> so far with no issues, but many new use cases need to have access to the set of names or to a specific Person using his name as key. This is why I have decided to store them using a Map.

After some research, I think the best way is to use Annotations @JsonDeserialize and @JsonSerialize with a JsonDeserializer and JsonSerializer as parameter respectively for the field children:

public class Person {

  private String id;

  @JsonSerialize(using=MySerializer.class)
  @JsonDeserialize(using=MyDeserializer.class)
  private Map<String, Person> friends;

  // lots of other fields
}

My question is: Does such a JsonSerializer/JsonDeserializer exist and if not, how do I define one?


edit: I have started implementing a custom Deserializer, but I get this exception:

com.fasterxml.jackson.databind.JsonMappingException: Class has no default (no arg) constructor

which is weird because I have defined a default constructor. Here is my custom Deserializer:

public class MyDeserializer extends JsonDeserializer<Map<String, Person>> {

    public MyDeserializer() {
    }

    @Override
    public Map<String, Person> deserialize(JsonParser jp, DeserializationContext ctxt)
      throws IOException, JsonProcessingException {
      JsonNode personsNodeArray = jp.getCodec().readTree(jp);
      Map<String, Person> newChildren = null;
      if (personsNodeArray.isArray() && personsNodeArray.size() > 0) {
        newChildren = new HashMap<String, Person>();
        for (JsonNode personNode : personsNodeArray) {
          String id = personNode.get("name").asText();
          // jsonMapper is a default ObjectMapper
          newChildren.put(id, jsonMapper.readValue(personNode.toString(), Person.class));
        }
      }
      return newChildren;
    }
  }

1 Answer 1

1

You can also consider reading children information as a collection of persons with subsequent conversion into a map. You can define a setter method (or a constructor parameter) to accept a List<Person> and then put each element into the Map<String, Person> children field. That would avoid unnecessary complexity of custom serialisation.

Here is an example:

public class JacksonChildren {
    public static final String JSON = "{\"name\":\"Bob\", \"children\":[{\"name\":\"Jimmmy\"}," +
            "{\"name\":\"Judy\"}]}";

    public static class Person {
        public String name;
        private Map<String, Person> children = new HashMap<>();

        public void setChildren(final List<Person> children) {
            for (Person p : children) {
                this.children.put(p.name, p);
            }
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", children=" + children +
                    '}';
        }
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.readValue(JSON, Person.class));
    }

}

Output:

Person{name='Bob', children={Judy=Person{name='Judy', children={}}, Jimmmy=Person{name='Jimmmy', children={}}}}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.