Usually, you would annotate the address field with @JsonUnwrapped to be unwrapped when serialized (and wrapped when deserialized). But as you cannot change your 3rd party classes, you have to do this on a mixin instead:
// Mixin for class Employee
abstract class EmployeeMixin {
@JsonUnwrapped public Address address;
}
Then, create a module that holds all your specific "extensions". This can be done by subclassing Module or SimpleModule, or by composing a SimpleModule as here:
SimpleModule module = new SimpleModule("Employee");
module.setMixInAnnotation(Employee.class, EmployeeMixin.class);
Third, register the module with your ObjectMapper:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
Last, have fun serializing/deserializing!
Self contained, complete example that subclasses SimpleModule:
public class TestJacksonMixin {
/* 3rd party */
public static class Employee {
public String name;
public Address address;
}
/* 3rd party */
public static class Address {
public String city;
}
/* Jackon Module for Employee */
public static class EmployeeModule extends SimpleModule {
abstract class EmployeeMixin {
@JsonUnwrapped
public Address address;
}
public EmployeeModule() {
super("Employee");
}
@Override
public void setupModule(SetupContext context) {
setMixInAnnotation(Employee.class, EmployeeMixin.class);
}
}
public static void main(String[] args) throws JsonProcessingException {
Employee emp = new Employee();
emp.name = "Bob";
emp.address = new Address();
emp.address.city = "New York";
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new EmployeeModule());
System.out.println(mapper.writeValueAsString(emp));
}
}
See Jackson Annotations