BeanPropertyDeserTest.java
package tools.jackson.databind.deser;
import java.util.*;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import tools.jackson.databind.*;
import tools.jackson.databind.annotation.*;
import tools.jackson.databind.exc.InvalidDefinitionException;
import tools.jackson.databind.exc.UnrecognizedPropertyException;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
import static tools.jackson.databind.testutil.DatabindTestUtil.*;
/**
* Tests for bean property detection and deserialization: field-backed
* properties, getter-as-setter collections/maps, overloaded setter
* methods, and static method exclusion.
*/
public class BeanPropertyDeserTest
{
/*
/**********************************************************
/* Helper classes for field-backed property tests
/**********************************************************
*/
static class SimpleFieldBean
{
public int x, y;
// not auto-detectable, not public
int z;
// ignored, not detectable either
@JsonIgnore public int a;
}
static class SimpleFieldBean2
{
@JsonDeserialize String[] values;
}
@JsonAutoDetect(fieldVisibility=Visibility.NONE)
static class NoAutoDetectBean
{
// not auto-detectable any more
public int z;
@JsonProperty("z")
public int _z;
}
// Let's test invalid bean too
static class DupFieldBean
{
public int z;
@JsonProperty("z")
public int _z;
}
public static class DupFieldBean2
{
@JsonProperty("foo")
public int _z;
@JsonDeserialize
int foo;
}
public static class OkDupFieldBean
extends SimpleFieldBean
{
@JsonProperty("x")
protected int myX = 10;
@SuppressWarnings("hiding")
public int y = 11;
}
abstract static class Abstract { }
static class Concrete extends Abstract
{
String value;
public Concrete(String v) { value = v; }
}
static class AbstractWrapper {
@JsonDeserialize(as=Concrete.class)
public Abstract value;
}
/*
/**********************************************************
/* Helper classes for setterless property tests
/**********************************************************
*/
static class CollectionBean
{
List<String> _values = new ArrayList<>();
public List<String> getValues() { return _values; }
}
static class MapBean
{
Map<String,Integer> _values = new HashMap<>();
public Map<String,Integer> getValues() { return _values; }
}
// testing to verify that field has precedence over getter, for lists
static class Dual
{
@JsonProperty("list") protected List<Integer> values = new ArrayList<>();
public Dual() { }
public List<Integer> getList() {
throw new IllegalStateException("Should not get called");
}
}
static class DataBean2692
{
final String val;
@JsonCreator
public DataBean2692(@JsonProperty(value = "val") String val) {
super();
this.val = val;
}
public String getVal() {
return val;
}
public List<String> getList() {
return new ArrayList<>();
}
@Override
public String toString() {
return "DataBean [val=" + val + "]";
}
}
/*
/**********************************************************
/* Helper classes for overloaded method tests
/**********************************************************
*/
static class BaseListBean
{
List<String> list;
BaseListBean() { }
public void setList(List<String> l) { list = l; }
}
static class ArrayListBean extends BaseListBean
{
ArrayListBean() { }
public void setList(ArrayList<String> l) { super.setList(l); }
}
static class NumberBean {
protected Object value;
public void setValue(Number n) { value = n; }
}
static class WasNumberBean extends NumberBean {
public void setValue(String str) { value = str; }
}
static class Overloaded739
{
protected Object _value;
@JsonProperty
public void setValue(String str) { _value = str; }
// no annotation, should not be chosen:
public void setValue(Object o) { throw new UnsupportedOperationException(); }
}
/**
* And then a Bean that is conflicting and should not work
*/
static class ConflictBean {
public void setA(ArrayList<Object> a) { }
public void setA(LinkedList<Object> a) { }
}
/*
/**********************************************************
/* Helper classes for static method exclusion tests
/**********************************************************
*/
static class StaticSetterBean
{
int _x;
public static void setX(int value) { throw new Error("Should NOT call static method"); }
@JsonProperty("x") public void assignX(int x) { _x = x; }
}
/*
/**********************************************************
/* Test methods, field-backed properties
/**********************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testSimpleAutoDetect() throws Exception
{
SimpleFieldBean result = MAPPER.readValue("{ \"x\" : -13 }",
SimpleFieldBean.class);
assertEquals(-13, result.x);
assertEquals(0, result.y);
}
@Test
public void testSimpleAnnotation() throws Exception
{
SimpleFieldBean2 bean = MAPPER.readValue("{ \"values\" : [ \"x\", \"y\" ] }",
SimpleFieldBean2.class);
String[] values = bean.values;
assertNotNull(values);
assertEquals(2, values.length);
assertEquals("x", values[0]);
assertEquals("y", values[1]);
}
@Test
public void testNoAutoDetect() throws Exception
{
NoAutoDetectBean bean = MAPPER.readValue("{ \"z\" : 7 }",
NoAutoDetectBean.class);
assertEquals(7, bean._z);
}
@Test
public void testTypeAnnotation() throws Exception
{
AbstractWrapper w = MAPPER.readValue("{ \"value\" : \"abc\" }",
AbstractWrapper.class);
Abstract bean = w.value;
assertNotNull(bean);
assertEquals(Concrete.class, bean.getClass());
assertEquals("abc", ((Concrete)bean).value);
}
@Test
public void testResolvedDups1() throws Exception
{
DupFieldBean result = MAPPER.readValue(a2q("{'z':3}"), DupFieldBean.class);
assertEquals(3, result._z);
assertEquals(0, result.z);
}
@Test
public void testFailingDups2() throws Exception
{
// Fails because both fields have explicit annotation
try {
DupFieldBean2 result = MAPPER.readValue(a2q("{'foo':28}"), DupFieldBean2.class);
fail("Should not pass but got: "+result);
} catch (InvalidDefinitionException e) {
verifyException(e, "Multiple fields representing property \"foo\"");
}
}
@Test
public void testOkFieldOverride() throws Exception
{
OkDupFieldBean result = MAPPER.readValue("{ \"x\" : 1, \"y\" : 2 }",
OkDupFieldBean.class);
assertEquals(1, result.myX);
assertEquals(2, result.y);
}
/*
/**********************************************************
/* Test methods, setterless properties (getter-as-setter)
/**********************************************************
*/
@Test
public void testSimpleSetterlessCollectionOk() throws Exception
{
CollectionBean result = jsonMapperBuilder()
.enable(MapperFeature.USE_GETTERS_AS_SETTERS)
.build()
.readValue
("{\"values\":[ \"abc\", \"def\" ]}", CollectionBean.class);
List<String> l = result._values;
assertEquals(2, l.size());
assertEquals("abc", l.get(0));
assertEquals("def", l.get(1));
}
/**
* Let's also verify that disabling the feature makes
* deserialization fail for setterless bean
*/
@Test
public void testSimpleSetterlessCollectionFailure() throws Exception
{
ObjectMapper m = jsonMapperBuilder().enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
assertFalse(m.isEnabled(MapperFeature.USE_GETTERS_AS_SETTERS));
// and now this should fail
try {
m.readValue
("{\"values\":[ \"abc\", \"def\" ]}", CollectionBean.class);
fail("Expected an exception");
} catch (UnrecognizedPropertyException e) {
// Not a good exception, ideally could suggest a need for
// a setter...?
verifyException(e, "Unrecognized property");
}
}
@Test
public void testSimpleSetterlessMapOk() throws Exception
{
MapBean result = jsonMapperBuilder()
.enable(MapperFeature.USE_GETTERS_AS_SETTERS)
.build()
.readValue
("{\"values\":{ \"a\": 15, \"b\" : -3 }}", MapBean.class);
Map<String,Integer> m = result._values;
assertEquals(2, m.size());
assertEquals(Integer.valueOf(15), m.get("a"));
assertEquals(Integer.valueOf(-3), m.get("b"));
}
@Test
public void testSimpleSetterlessMapFailure() throws Exception
{
ObjectMapper m = jsonMapperBuilder()
.disable(MapperFeature.USE_GETTERS_AS_SETTERS)
.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
// so this should fail now without a setter
try {
m.readValue
("{\"values\":{ \"a\":3 }}", MapBean.class);
fail("Expected an exception");
} catch (UnrecognizedPropertyException e) {
verifyException(e, "Unrecognized property");
}
}
/* Test for [JACKSON-328], precedence of "getter-as-setter" (for Lists) versus
* field for same property.
*/
@Test
public void testSetterlessPrecedence() throws Exception
{
ObjectMapper m = jsonMapperBuilder()
.enable(MapperFeature.USE_GETTERS_AS_SETTERS)
.build();
Dual value = m.readValue("{\"list\":[1,2,3]}", Dual.class);
assertNotNull(value);
assertEquals(3, value.values.size());
}
// [databind#2692]
@Test
void issue2692() throws Exception {
String json = "{\"list\":[\"11\"],\"val\":\"VAL2\"}";
DataBean2692 out = MAPPER.readerFor(DataBean2692.class).readValue(json);
assertNotNull(out);
}
/*
/**********************************************************
/* Test methods, overloaded methods
/**********************************************************
*/
/**
* It should be ok to overload with specialized
* version; more specific method should be used.
*/
@Test
public void testSpecialization() throws Exception
{
ArrayListBean bean = MAPPER.readValue
("{\"list\":[\"a\",\"b\",\"c\"]}", ArrayListBean.class);
assertNotNull(bean.list);
assertEquals(3, bean.list.size());
assertEquals(ArrayList.class, bean.list.getClass());
assertEquals("a", bean.list.get(0));
assertEquals("b", bean.list.get(1));
assertEquals("c", bean.list.get(2));
}
/**
* As per [JACKSON-255], should also allow more general overriding,
* as long as there are no in-class conflicts.
*/
@Test
public void testOverride() throws Exception
{
WasNumberBean bean = MAPPER.readValue
("{\"value\" : \"abc\"}", WasNumberBean.class);
assertNotNull(bean);
assertEquals("abc", bean.value);
}
// for [JACKSON-739]
@Test
public void testConflictResolution() throws Exception
{
Overloaded739 bean = MAPPER.readValue
("{\"value\":\"abc\"}", Overloaded739.class);
assertNotNull(bean);
assertEquals("abc", bean._value);
}
/**
* For genuine setter conflict, an exception is to be thrown.
*/
@Test
public void testSetterConflict() throws Exception
{
try {
MAPPER.readValue("{ }", ConflictBean.class);
} catch (Exception e) {
verifyException(e, "Conflicting setter definitions");
}
}
/*
/**********************************************************
/* Test methods, static method exclusion
/**********************************************************
*/
@Test
public void testStaticSetterIgnored() throws Exception
{
ObjectMapper m = new ObjectMapper();
// should not care about static setter...
StaticSetterBean result = m.readValue("{ \"x\":3}", StaticSetterBean.class);
assertEquals(3, result._x);
}
}