BuilderWithTypeParametersTest.java
package com.fasterxml.jackson.databind.deser.builder;
import java.util.LinkedHashMap;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.a2q;
import static com.fasterxml.jackson.databind.testutil.DatabindTestUtil.jsonMapperBuilder;
// [databind#921]: support infering type parameters from Builder
public class BuilderWithTypeParametersTest
{
public static class MyPOJO {
public String x;
public String y;
@JsonCreator
public MyPOJO(@JsonProperty("x") String x, @JsonProperty("y") String y) {
this.x = x;
this.y = y;
}
}
@JsonDeserialize(builder = MyGenericPOJO.Builder.class)
public static class MyGenericPOJO<T> {
List<T> data;
MyGenericPOJO(List<T> d) {
data = d;
}
public List<T> getData() {
return data;
}
// 28-Apr-2020, tatu: Note that as per [databind#921] the NAME of
// type variable here MUST match that of enclosing class. This has
// no semantic meaning to JDK or javac, but internally
// `MapperFeature.INFER_BUILDER_TYPE_BINDINGS` relies on this -- but
// can not really validate it. So user just has to rely on bit of
// black magic to use generic types with builders.
public static class Builder<T> {
private List<T> data;
public Builder<T> withData(List<T> d) {
data = d;
return this;
}
public MyGenericPOJO<T> build() {
return new MyGenericPOJO<T>(data);
}
}
}
// 05-Sep-2020, tatu: This is not correct and cannot be made to work --
// assumption is that static method binding `T` would somehow refer to
// class type parameter `T`: this is not true.
/*
public static class MyGenericPOJOWithCreator<T> {
List<T> data;
MyGenericPOJOWithCreator(List<T> d) {
data = d;
}
@JsonCreator
public static <T> MyGenericPOJOWithCreator<T> create(@JsonProperty("data") List<T> data) {
return new MyGenericPOJOWithCreator.Builder<T>().withData(data).build();
}
public List<T> getData() {
return data;
}
public static class Builder<T> {
private List<T> data;
public Builder<T> withData(List<T> d) {
data = d;
return this;
}
public MyGenericPOJOWithCreator<T> build() {
return new MyGenericPOJOWithCreator<T>(data);
}
}
}
*/
@Test
public void testWithBuilderInferringBindings() throws Exception {
final ObjectMapper mapper = jsonMapperBuilder()
.enable(MapperFeature.INFER_BUILDER_TYPE_BINDINGS)
.build();
final String json = a2q("{ 'data': [ { 'x': 'x', 'y': 'y' } ] }");
final MyGenericPOJO<MyPOJO> deserialized =
mapper.readValue(json, new TypeReference<MyGenericPOJO<MyPOJO>>() {});
assertEquals(1, deserialized.data.size());
Object ob = deserialized.data.get(0);
assertNotNull(ob);
assertEquals(MyPOJO.class, ob.getClass());
}
@Test
public void testWithBuilderWithoutInferringBindings() throws Exception {
final ObjectMapper mapper = jsonMapperBuilder()
.disable(MapperFeature.INFER_BUILDER_TYPE_BINDINGS)
.build();
final String json = a2q("{ 'data': [ { 'x': 'x', 'y': 'y' } ] }");
final MyGenericPOJO<MyPOJO> deserialized =
mapper.readValue(json, new TypeReference<MyGenericPOJO<MyPOJO>>() {});
assertEquals(1, deserialized.data.size());
Object ob = deserialized.data.get(0);
assertNotNull(ob);
assertEquals(LinkedHashMap.class, ob.getClass());
}
// 05-Sep-2020, tatu: see above for reason why this can not work
/*
@Test
public void testWithCreator() throws Exception {
final ObjectMapper mapper = new ObjectMapper();
final String json = a2q("{ 'data': [ { 'x': 'x', 'y': 'y' } ] }");
final MyGenericPOJOWithCreator<MyPOJO> deserialized =
mapper.readValue(json,
new TypeReference<MyGenericPOJOWithCreator<MyPOJO>>() {});
assertEquals(1, deserialized.data.size());
Object ob = deserialized.data.get(0);
assertNotNull(ob);
assertEquals(MyPOJO.class, ob.getClass());
}
*/
}