Unwrap only some properties with Jackson

2.7k views Asked by At

Assuming I have this objects:

class Person {
   String name;
   Household getHousehold();
}

class Household {
   Set<Address> getAddresses();
   String householdId;
}

which would normally be serialized as follows

{
  "name": "XXX",
  "household": {
    "addresses": [...]
  }
}

Is there a way to configure Jackson with annotations / mix-ins to obtain this (ie. without using DTO) ?

{
  "name": "XXX",
  "addresses": [...],
  "household": {
    "householdId": 123
  }
}
1

There are 1 answers

4
Alex Ciocan On BEST ANSWER

You can configure the unwrapping of a specific property by both using mixins and annotations:

1. Mixins

Assuming you define the following mixin:

public abstract class UnwrappedAddresses {

        @JsonUnwrapped
        public abstract Household getHouseHold();

    }

And then add a custom module to your objectMapper which applies the mixin to the Person class as follows:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper .registerModule(new SimpleModule() {
            @Override
            public void setupModule(SetupContext context) {
                context.setMixInAnnotations(Person.class, UnwrappedAddresses.class);
            }

        });

This approach does not change the Household serialization as a single item, but just unwraps a household item when it's encapsulated in a Person object.

2. Annotations

Just add @JsonUnwrapped to your getHouseHold() method.

EDIT: After post changes.

What you want is basically to change the output of the json, which can be done by using the @JsonAnyGetter annotation(which can dynamically add new properties to your pojo).

Your expected result can be achieved by ignoring the household property and unwrapping it with the help of the @JsonAnyGetter.

@JsonIgnoreProperties("houseHold")
public static class Person {
   String name;

   Household houseHold;

    @JsonAnyGetter
    public Map<String,Object> properties(){
      Map<String,Object> additionalProps=new HashMap<>();
      additionalProps.put("addresses", new ArrayList<>(houseHold.getAddresses()));
      Map<String,Object> houseHolProps=new HashMap<>();
      houseHolProps.put("houseHoldId", houseHold.id);
      additionalProps.put("houseHold", houseHolProps);
      return additionalProps;
     }
        ..getters&setters omitted
}

Which would after serialization return

{"name":"name",
 "houseHold":{"houseHoldId":0},
 "addresses":[
         {"houseNo":2,"street":"abc"},
         {"houseNo":1,"street":"str"}
  ]
 }