2

How can I map a flat map to a nested pojo? I've tried using this, however I get an unrecognized field exception on the field sword.

Map<String, Object> values = ...;
ObjectMapper mapper = new ObjectMapper();
mapper.readValue(mapper.writeValueAsString(values), Person.class);

I have this dummy json:

{
  "firstName": "Arya",
  "lastName": "Stark",
  "gender": "Female",
  "sword" : "Excalibur",
  "shield": "Mighty Shield"
}

a person class:

@Data
@AllArgsConstructor
public class Person {

 private String firstName;
 private String lastName;
 private Equipment equipments;

}

and an equipment class:

@Data
@AllArgsConstructor
public class Equipment {

 private String sword;
 private String shield;

}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62

3 Answers3

3

I see this way to solve this problem:

public class Test {
    public static void main(String[] args) {
        Map<String, Object> values = new HashMap<>();

        values.put("firstName", "Arya");
        values.put("lastName", "Stark");
        values.put("gender", "Female");
        values.put("sword", "Excalibur");
        values.put("shield", "Mighty Shield");
        ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        Person person = mapper.convertValue(values, Person.class);
        person.setEquipments(mapper.convertValue(values, Equipment.class));

        System.out.println(person);

    }
}

Of course it is not one line deserialization but it works. Result:

Person(firstName=Arya, lastName=Stark, equipments=Equipment(sword=Excalibur, shield=Mighty Shield))

Note: add @NoArgsConstructor to your POJO, it is required by Jackson.

Dmitry Gorkovets
  • 2,208
  • 1
  • 10
  • 19
  • what if returning object is List of Person rather than Person, how can equipment object is saved in its appropriate Person object. – sadia Aug 07 '18 at 05:44
0

Meanwhile jackson added @JsonUnwrapped and lombok added @Jacksonized this reduces your overhead to a minimum of:

@Value
@Builder
@Jacksonized
public class Person {

  private String firstName;
  private String lastName;
  @JsonUnwrapped
  private Equipment equipments;
}

Note: @Jacksonized is only necessary in combination with @Builder. But this prevents us from using the @NoArgsConstructor

Christian
  • 1,664
  • 1
  • 23
  • 43
-1

I think you have a mistake when you collect attributes for different classes into one map. Why did you do that?

It's easy transform json to object with nested classes if your json has the same structure. In your example it should be:

{ "person": { "firstName": "name", "lastName": "name2", "gender": "male", "equipment": { "sword": "s", "shield": "s2" } } }

That json can be easily transformed to Person.java by objectMapper.readValue(json, Person.class);

nick318
  • 575
  • 4
  • 18
  • I need to aggregate the json for other pojos too, so I need it to be as generic as possible. –  Feb 02 '18 at 10:48
  • Then, your map should contain value as a whole json, not an attribute. In that case you can get by key well prepared json and convert it to pojo. – nick318 Feb 02 '18 at 10:51
  • @NikitaSalomatin, maybe this JSON was constructed from CSV file or table from Relation database? In this case it is reasonable to have dictionary map as input structure. – Dmitry Gorkovets Feb 02 '18 at 11:03