I need to be able to create a Java POJO from a JSON object when I only have an interface that can't be changed. I'm hoping that Mixins can help make this possible. I created a Mixin that hopefully will work but can't get Jackson to use it.
It appears that Jackson is ignoring the Mixin I am defining for both an Interface and an Implementation. The test failures are what I would expect without the Mixin added to the ObjectMapper.
Below is the simplest example that shows the problem. The classes are each in their own package. The real uses case is much more complex, including Lists of interfaces. I am using Jackson 2.10.3.
Any suggestions on what I'm doing wrong?
Timothy
What doesn't work
The interface reader test fails with InvalidDefinitionException: Cannot construct instance of model.Level4 (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
Of secondary importance, the Mixin defines a new label (nameTest) for the name field which should be reflected in the output from writeValueAsString. It outputs the field with the original value for the label (name).
Interface
public interface Level4 {
public Long getId();
public void setId(Long id);
public String getName();
public void setName(String name);
}
Implementation
public class Level4Impl implements Level4 {
private Long id;
private String name;
@Override
public Long getId() {
return id;
}
@Override
public void setId(Long id) {
this.id = id;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}
Mixin
public abstract class Level4Mixin {
public Level4Mixin(
@JsonProperty("id") Long id,
@JsonProperty("nameTest") String name) { }
}
Unit Test
class Level4MixinTest {
private ObjectMapper mapper;
@BeforeEach
void setUp() throws Exception {
mapper = new ObjectMapper();
mapper.addMixIn(Level4.class, Level4Mixin.class);
mapper.addMixIn(Level4Impl.class, Level4Mixin.class);
}
@Test
void test_InterfaceWrite() throws JsonProcessingException {
Level4 lvl4 = new Level4Impl();
lvl4.setId(1L);
lvl4.setName("test");
String json = mapper.writeValueAsString(lvl4);
assertNotNull(json);
assertTrue(json.contains("nameTest"));
}
@Test
void test_InterfaceRead() throws JsonProcessingException {
String json = "{\"id\":1,\"nameTest\":\"test\"}";
assertDoesNotThrow(() -> {
Level4 parsed = mapper.readValue(json, Level4.class);
assertNotNull(parsed);
});
}
@Test
void test_ImplWrite() throws JsonProcessingException {
Level4Impl lvl4 = new Level4Impl();
lvl4.setId(1L);
lvl4.setName("test");
String json = mapper.writeValueAsString(lvl4);
assertNotNull(json);
assertTrue(json.contains("nameTest"));
}
@Test
void test_ImplRead() {
String json = "{\"id\":1,\"nameTest\":\"test\"}";
assertDoesNotThrow(() -> {
Level4Impl parsed = mapper.readValue(json, Level4Impl.class);
assertNotNull(parsed);
});
}
}