SetterConflictTest.java
package com.fasterxml.jackson.databind.introspect;
import java.util.List;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
// mostly for [databind#1033]
public class SetterConflictTest extends DatabindTestUtil
{
// Should prefer primitives over Strings, more complex types, by default
static class Issue1033Bean {
public int value;
public void setValue(int v) { value = v; }
public void setValue(Issue1033Bean foo) {
throw new Error("Should not get called");
}
}
// [databind#2979]
static class DuplicateSetterBean2979 {
Object value;
public void setBloop(Boolean bloop) {
throw new Error("Wrong setter!");
}
@JsonSetter
public void setBloop(Object bloop) {
value = bloop;
}
}
// [databind#3125]: As per existing (2.7+) logic we SHOULD tie-break
// in favor of `String` but code up until 2.12 short-circuited early fail
static class DupSetter3125Bean {
String str;
public void setValue(Integer value) { throw new RuntimeException("Integer: wrong!"); }
public void setValue(Boolean value) { throw new RuntimeException("Boolean: wrong!"); }
public void setValue(String value) { str = value; }
}
static class DupSetter3125BeanFail {
public void setValue(Integer value) { throw new RuntimeException("Integer: wrong!"); }
public void setValue(Boolean value) { throw new RuntimeException("Boolean: wrong!"); }
public void setValue(List<String> value) { throw new RuntimeException("List: wrong!"); }
}
/*
/**********************************************************************
/* Test methods
/**********************************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
// [databind#1033]
@Test
public void testSetterPriority() throws Exception
{
Issue1033Bean bean = MAPPER.readValue(a2q("{'value':42}"),
Issue1033Bean.class);
assertEquals(42, bean.value);
}
// [databind#2979]
@Test
public void testConflictingSetters() throws Exception
{
ObjectMapper mapper = jsonMapperBuilder()
.propertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE)
.build();
DuplicateSetterBean2979 result = mapper.readValue(a2q("{'bloop':true}"),
DuplicateSetterBean2979.class);
assertEquals(Boolean.TRUE, result.value);
}
// [databind#3125]
@Test
public void testDuplicateSetterResolutionOk() throws Exception
{
POJOPropertiesCollector coll = collector(MAPPER, DupSetter3125Bean.class,
false);
final List<BeanPropertyDefinition> props = coll.getProperties();
assertEquals(1, props.size());
POJOPropertyBuilder prop = (POJOPropertyBuilder) props.get(0);
assertEquals("value", prop.getName());
// but this failed
AnnotatedMethod m = prop.getSetter();
assertNotNull(m);
assertEquals(String.class, m.getRawParameterType(0));
// and then actual usage too
DupSetter3125Bean value = MAPPER.readValue(a2q("{'value':'foo'}"),
DupSetter3125Bean.class);
assertEquals("foo", value.str);
}
// [databind#3125]: caught case
@Test
public void testDuplicateSetterResolutionFail() throws Exception
{
try {
MAPPER.readValue(a2q("{'value':'foo'}"),
DupSetter3125BeanFail.class);
fail("Should not pass");
} catch (InvalidDefinitionException e) {
verifyException(e, "Conflicting setter definitions for property \"value\"");
}
}
/*
/**********************************************************************
/* Helper methods
/**********************************************************************
*/
protected POJOPropertiesCollector collector(ObjectMapper m0,
Class<?> cls, boolean forSerialization)
{
BasicClassIntrospector bci = new BasicClassIntrospector();
// no real difference between serialization, deserialization, at least here
if (forSerialization) {
return bci.collectProperties(m0.getSerializationConfig(),
m0.constructType(cls), null, true);
}
return bci.collectProperties(m0.getDeserializationConfig(),
m0.constructType(cls), null, false);
}
}