Skip to content

Commit f12f65d

Browse files
committed
Fixed FasterXML#2729 conflicting getters/setters when not respecting capitalization
1 parent b83ab88 commit f12f65d

File tree

3 files changed

+154
-23
lines changed

3 files changed

+154
-23
lines changed

src/main/java/com/fasterxml/jackson/databind/introspect/POJOPropertyBuilder.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,10 @@ protected int _getterPriority(AnnotatedMethod m)
580580
{
581581
final String name = m.getName();
582582
// [databind#238]: Also, regular getters have precedence over "is-getters"
583-
if (name.startsWith("get") && name.length() > 3) {
584-
// should we check capitalization?
583+
if (name.startsWith("get") && name.length() > 3 && Character.isUpperCase(name.charAt(3))) {
585584
return 1;
586585
}
587-
if (name.startsWith("is") && name.length() > 2) {
586+
if (name.startsWith("is") && name.length() > 2 && Character.isUpperCase(name.charAt(2))) {
588587
return 2;
589588
}
590589
return 3;
@@ -593,8 +592,7 @@ protected int _getterPriority(AnnotatedMethod m)
593592
protected int _setterPriority(AnnotatedMethod m)
594593
{
595594
final String name = m.getName();
596-
if (name.startsWith("set") && name.length() > 3) {
597-
// should we check capitalization?
595+
if (name.startsWith("set") && name.length() > 3 && Character.isUpperCase(name.charAt(3))) {
598596
return 1;
599597
}
600598
return 2;
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package com.fasterxml.jackson.databind.introspect;
2+
3+
import com.fasterxml.jackson.databind.BaseMapTest;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
6+
import java.lang.reflect.Field;
7+
8+
// [databind#2729]
9+
public class PropertyNameSetterGetterConflictTest extends BaseMapTest {
10+
11+
private final ObjectMapper MAPPER = mapperWithScalaModule();
12+
13+
// Should work with setters named exactly like the property
14+
static class Issue2729BeanWithFieldNameSetterGetter {
15+
private String value;
16+
17+
public void value(String v) { value = v; }
18+
public String value() { return value; }
19+
}
20+
21+
// Should prefer java bean naming convention over property names
22+
static class Issue2729BeanWithoutCaseSensitivityBean {
23+
private String value;
24+
25+
public void value(String v) { throw new Error("Should not get called"); }
26+
public String value() { throw new Error("Should not get called"); }
27+
public void setValue(String v) { value = v; }
28+
public String getValue() { return value; }
29+
}
30+
31+
// Should prefer java bean naming convention over property names while respecting case-sensitivity
32+
static class Issue2729WithCaseSensitivityBean {
33+
private String settlementDate;
34+
private String getaways;
35+
private Boolean island;
36+
37+
public void settlementDate(String v) { throw new Error("Should not get called"); }
38+
public String settlementDate() { throw new Error("Should not get called"); }
39+
public void setSettlementDate(String v) { settlementDate = v; }
40+
public String getSettlementDate() { return settlementDate; }
41+
42+
public void getaways(String v) { throw new Error("Should not get called"); }
43+
public String getaways() { throw new Error("Should not get called"); }
44+
public void setGetaways(String v) { getaways = v; }
45+
public String getGetaways() { return getaways; }
46+
47+
public void island(Boolean v) { throw new Error("Should not get called"); }
48+
public Boolean island() { throw new Error("Should not get called"); }
49+
public void setIsland(Boolean v) { island = v; }
50+
public Boolean isIsland() { return island; }
51+
}
52+
53+
/*
54+
/**********************************************************
55+
/* Test methods
56+
/**********************************************************
57+
*/
58+
59+
public void testSetterPriorityForFieldNameSetter() throws Exception
60+
{
61+
Issue2729BeanWithFieldNameSetterGetter bean = MAPPER.readValue(aposToQuotes("{'value':'42'}"),
62+
Issue2729BeanWithFieldNameSetterGetter.class);
63+
assertEquals("42", bean.value);
64+
}
65+
66+
public void testSetterPriorityForJavaBeanNamingConvention() throws Exception
67+
{
68+
Issue2729BeanWithoutCaseSensitivityBean bean = MAPPER.readValue(aposToQuotes("{'value':'42'}"),
69+
Issue2729BeanWithoutCaseSensitivityBean.class);
70+
assertEquals("42", bean.value);
71+
}
72+
73+
public void testSetterPriorityForJavaBeanNamingConventionWhileRespectingCaseSensitivity() throws Exception
74+
{
75+
final Issue2729WithCaseSensitivityBean bean = MAPPER.readValue(aposToQuotes("{'settlementDate':'42'}"),
76+
Issue2729WithCaseSensitivityBean.class);
77+
assertEquals("42", bean.settlementDate);
78+
}
79+
80+
public void testSetterPriorityForJavaBeanNamingConventionWhileRespectingCaseSensitivity2() throws Exception
81+
{
82+
final Issue2729WithCaseSensitivityBean bean = MAPPER.readValue(aposToQuotes("{'island':true}"),
83+
Issue2729WithCaseSensitivityBean.class);
84+
assertEquals(Boolean.TRUE, bean.island);
85+
}
86+
87+
public void testGetterPriorityForFieldNameSetter() throws Exception
88+
{
89+
final Issue2729BeanWithFieldNameSetterGetter bean = new Issue2729BeanWithFieldNameSetterGetter();
90+
bean.value("42");
91+
assertEquals(aposToQuotes("{'value':'42'}"), MAPPER.writeValueAsString(bean));
92+
}
93+
94+
public void testGetterPriorityForJavaBeanNamingConvention() throws Exception
95+
{
96+
97+
final Issue2729BeanWithoutCaseSensitivityBean bean = new Issue2729BeanWithoutCaseSensitivityBean();
98+
bean.setValue("42");
99+
assertEquals(aposToQuotes("{'value':'42'}"), MAPPER.writeValueAsString(bean));
100+
}
101+
102+
public void testGetterPriorityForJavaBeanNamingConventionWhileRespectingCaseSensitivity() throws Exception
103+
{
104+
final Issue2729WithCaseSensitivityBean bean = new Issue2729WithCaseSensitivityBean();
105+
bean.setGetaways("42");
106+
assertEquals(aposToQuotes("{'settlementDate':null,'getaways':'42','island':null}"), MAPPER.writeValueAsString(bean));
107+
}
108+
109+
public void testGetterPriorityForJavaBeanNamingConventionWhileRespectingCaseSensitivity2() throws Exception
110+
{
111+
final Issue2729WithCaseSensitivityBean bean = new Issue2729WithCaseSensitivityBean();
112+
bean.setIsland(true);
113+
assertEquals(aposToQuotes("{'settlementDate':null,'getaways':null,'island':true}"), MAPPER.writeValueAsString(bean));
114+
}
115+
116+
/*
117+
/**********************************************************
118+
/* Helper methods
119+
/**********************************************************
120+
*/
121+
122+
private ObjectMapper mapperWithScalaModule()
123+
{
124+
ObjectMapper m = new ObjectMapper();
125+
m.setAnnotationIntrospector(new ScalaLikeAnnotationIntrospector());
126+
return m;
127+
}
128+
129+
static class ScalaLikeAnnotationIntrospector extends JacksonAnnotationIntrospector
130+
{
131+
private static final long serialVersionUID = 1L;
132+
133+
@Override
134+
public String findImplicitPropertyName(AnnotatedMember member) {
135+
if (member instanceof AnnotatedMethod) {
136+
return hasCorrespondingProperty(((AnnotatedMethod) member)) ? member.getName() : null;
137+
}
138+
return null;
139+
}
140+
141+
private static boolean hasCorrespondingProperty(AnnotatedMethod method) {
142+
final String name = method.getName();
143+
for (Field f : method.getDeclaringClass().getDeclaredFields()) {
144+
if (name.equals(f.getName())) {
145+
return true;
146+
}
147+
}
148+
return false;
149+
}
150+
}
151+
}

src/test/java/com/fasterxml/jackson/databind/introspect/TestPropertyConflicts.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@
1212
*/
1313
public class TestPropertyConflicts extends BaseMapTest
1414
{
15-
// error message for conflicting getters sub-optimal
16-
static class BeanWithConflict
17-
{
18-
public int getX() { return 3; }
19-
public boolean getx() { return false; }
20-
}
21-
2215
// [databind#238]
2316
protected static class Getters1A
2417
{
@@ -88,17 +81,6 @@ public String getStr() {
8881
/**********************************************************
8982
*/
9083

91-
public void testFailWithDupProps() throws Exception
92-
{
93-
BeanWithConflict bean = new BeanWithConflict();
94-
try {
95-
String json = objectWriter().writeValueAsString(bean);
96-
fail("Should have failed due to conflicting accessor definitions; got JSON = "+json);
97-
} catch (JsonProcessingException e) {
98-
verifyException(e, "Conflicting getter definitions");
99-
}
100-
}
101-
10284
// [databind#238]: ok to have getter, "isGetter"
10385
public void testRegularAndIsGetter() throws Exception
10486
{

0 commit comments

Comments
 (0)