ObjectIdWithTypeInfo4014Test.java
package tools.jackson.databind.objectid;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import tools.jackson.databind.*;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Test for [databind#4014]: combining {@code @JsonTypeInfo(include = As.PROPERTY)}
* with {@code @JsonIdentityInfo(generator = PropertyGenerator.class)} on an interface
* should work for deserialization.
*/
public class ObjectIdWithTypeInfo4014Test extends DatabindTestUtil
{
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@c")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "@id")
public interface BaseEntity {
@JsonProperty("@id")
Integer getId();
}
// Immutable classes: constructor-only @id, no setter
static class Foo implements BaseEntity {
private final Integer id;
private Bar bar;
@JsonCreator
public Foo(@JsonProperty("@id") Integer id) {
this.id = id;
}
@Override @JsonProperty("@id") public Integer getId() { return id; }
public Bar getBar() { return bar; }
public void setBar(Bar bar) { this.bar = bar; }
}
static class Bar implements BaseEntity {
private final Integer id;
private Foo foo;
@JsonCreator
public Bar(@JsonProperty("@id") Integer id) {
this.id = id;
}
@Override @JsonProperty("@id") public Integer getId() { return id; }
public Foo getFoo() { return foo; }
public void setFoo(Foo foo) { this.foo = foo; }
}
// Mutable classes: default constructor + setters
static class FooWithSetter implements BaseEntity {
private Integer id;
private BarWithSetter bar;
public FooWithSetter() { }
@Override @JsonProperty("@id") public Integer getId() { return id; }
@JsonProperty("@id") public void setId(Integer id) { this.id = id; }
public BarWithSetter getBar() { return bar; }
public void setBar(BarWithSetter bar) { this.bar = bar; }
}
static class BarWithSetter implements BaseEntity {
private Integer id;
private FooWithSetter foo;
public BarWithSetter() { }
@Override @JsonProperty("@id") public Integer getId() { return id; }
@JsonProperty("@id") public void setId(Integer id) { this.id = id; }
public FooWithSetter getFoo() { return foo; }
public void setFoo(FooWithSetter foo) { this.foo = foo; }
}
// Wrapper-array variants: exercises AsArrayTypeDeserializer fix
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.WRAPPER_ARRAY, property = "@c")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "@id")
public interface WrapperArrayEntity {
@JsonProperty("@id")
Integer getId();
}
static class WrapFoo implements WrapperArrayEntity {
private final Integer id;
private WrapBar bar;
@JsonCreator
public WrapFoo(@JsonProperty("@id") Integer id) { this.id = id; }
@Override @JsonProperty("@id") public Integer getId() { return id; }
public WrapBar getBar() { return bar; }
public void setBar(WrapBar bar) { this.bar = bar; }
}
static class WrapBar implements WrapperArrayEntity {
private final Integer id;
private WrapFoo foo;
@JsonCreator
public WrapBar(@JsonProperty("@id") Integer id) { this.id = id; }
@Override @JsonProperty("@id") public Integer getId() { return id; }
public WrapFoo getFoo() { return foo; }
public void setFoo(WrapFoo foo) { this.foo = foo; }
}
private final ObjectMapper MAPPER = newJsonMapper();
// [databind#4014]: simple round-trip via interface (setter-based)
@Test
public void testSimpleDeserializationViaInterface() throws Exception
{
FooWithSetter foo = new FooWithSetter();
foo.setId(1);
String json = MAPPER.writeValueAsString(foo);
BaseEntity result = MAPPER.readValue(json, BaseEntity.class);
assertNotNull(result);
assertInstanceOf(FooWithSetter.class, result);
assertEquals(1, ((FooWithSetter) result).getId());
}
// [databind#4014]: simple round-trip via interface (constructor-based)
@Test
public void testSimpleDeserializationWithCreator() throws Exception
{
Foo foo = new Foo(1);
String json = MAPPER.writeValueAsString(foo);
BaseEntity result = MAPPER.readValue(json, BaseEntity.class);
assertNotNull(result);
assertInstanceOf(Foo.class, result);
assertEquals(1, ((Foo) result).getId());
}
// [databind#4014]: circular references with setter-based classes
@Test
public void testCircularReferenceWithSetters() throws Exception
{
FooWithSetter foo = new FooWithSetter();
foo.setId(1);
BarWithSetter bar = new BarWithSetter();
bar.setId(2);
foo.setBar(bar);
bar.setFoo(foo);
String json = MAPPER.writeValueAsString(foo);
BaseEntity result = MAPPER.readValue(json, BaseEntity.class);
assertNotNull(result);
assertInstanceOf(FooWithSetter.class, result);
FooWithSetter resultFoo = (FooWithSetter) result;
assertEquals(1, resultFoo.getId());
assertNotNull(resultFoo.getBar());
assertEquals(2, resultFoo.getBar().getId());
assertSame(resultFoo, resultFoo.getBar().getFoo());
}
// [databind#4014]: circular references with constructor-based classes
@Test
public void testCircularReferenceWithCreator() throws Exception
{
Foo foo = new Foo(1);
Bar bar = new Bar(2);
foo.setBar(bar);
bar.setFoo(foo);
String json = MAPPER.writeValueAsString(foo);
BaseEntity result = MAPPER.readValue(json, BaseEntity.class);
assertNotNull(result);
assertInstanceOf(Foo.class, result);
Foo resultFoo = (Foo) result;
assertEquals(1, resultFoo.getId());
assertNotNull(resultFoo.getBar());
assertEquals(2, resultFoo.getBar().getId());
assertSame(resultFoo, resultFoo.getBar().getFoo());
}
// [databind#4014]: simple round-trip with WRAPPER_ARRAY
@Test
public void testSimpleDeserializationWrapperArray() throws Exception
{
WrapFoo foo = new WrapFoo(1);
String json = MAPPER.writeValueAsString(foo);
WrapperArrayEntity result = MAPPER.readValue(json, WrapperArrayEntity.class);
assertNotNull(result);
assertInstanceOf(WrapFoo.class, result);
assertEquals(1, ((WrapFoo) result).getId());
}
// [databind#4014]: circular references with WRAPPER_ARRAY
@Test
public void testCircularReferenceWrapperArray() throws Exception
{
WrapFoo foo = new WrapFoo(1);
WrapBar bar = new WrapBar(2);
foo.setBar(bar);
bar.setFoo(foo);
String json = MAPPER.writeValueAsString(foo);
WrapperArrayEntity result = MAPPER.readValue(json, WrapperArrayEntity.class);
assertNotNull(result);
assertInstanceOf(WrapFoo.class, result);
WrapFoo resultFoo = (WrapFoo) result;
assertEquals(1, resultFoo.getId());
assertNotNull(resultFoo.getBar());
assertEquals(2, resultFoo.getBar().getId());
assertSame(resultFoo, resultFoo.getBar().getFoo());
}
}