Skip to content

Commit d051497

Browse files
committed
Fix #1886
1 parent 35e5d0e commit d051497

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

release-notes/VERSION-2.x

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ Project: jackson-databind
88

99
#792: Deserialization Not Working Right with Generic Types and Builders
1010
(reported by Mike G; fix contributed by Ville K)
11+
#1886: Allow use of `@JsonFormat(with=JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)`
12+
on Class
1113
#1919: Abstract class included as part of known type ids for error message
1214
when using JsonSubTypes
1315
(reported by Incara@github)

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBuilder.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,8 @@ public JsonDeserializer<?> build()
351351
Collection<SettableBeanProperty> props = _properties.values();
352352
_fixAccess(props);
353353
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
354-
_collectAliases(props));
354+
_collectAliases(props),
355+
_findCaseInsensitivity());
355356
propertyMap.assignIndexes();
356357

357358
// view processing must be enabled if:
@@ -427,7 +428,8 @@ public JsonDeserializer<?> buildBuilderBased(JavaType valueType, String expBuild
427428
Collection<SettableBeanProperty> props = _properties.values();
428429
_fixAccess(props);
429430
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
430-
_collectAliases(props));
431+
_collectAliases(props),
432+
_findCaseInsensitivity());
431433
propertyMap.assignIndexes();
432434

433435
boolean anyViews = !_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION);
@@ -531,4 +533,15 @@ protected Map<String,List<PropertyName>> _collectAliases(Collection<SettableBean
531533
}
532534
return mapping;
533535
}
536+
537+
// @since 2.12
538+
protected boolean _findCaseInsensitivity() {
539+
// 07-May-2020, tatu: First find combination of per-type config overrides (higher
540+
// precedence) and per-type annotations (lower):
541+
JsonFormat.Value format = _beanDesc.findExpectedFormat(null);
542+
// and see if any of those has explicit definition; if not, use global baseline default
543+
Boolean B = format.getFeature(JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
544+
return (B == null) ? _config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
545+
: B.booleanValue();
546+
}
534547
}

src/main/java/com/fasterxml/jackson/databind/deser/impl/BeanPropertyMap.java

+14
Original file line numberDiff line numberDiff line change
@@ -268,9 +268,23 @@ private final static int findSize(int size)
268268
return result;
269269
}
270270

271+
/**
272+
* @since 2.12
273+
*/
274+
public static BeanPropertyMap construct(MapperConfig<?> config,
275+
Collection<SettableBeanProperty> props,
276+
Map<String,List<PropertyName>> aliasMapping,
277+
boolean caseInsensitive) {
278+
return new BeanPropertyMap(caseInsensitive,
279+
props, aliasMapping,
280+
config.getLocale());
281+
}
282+
271283
/**
272284
* @since 2.11
285+
* @deprecated since 2.12
273286
*/
287+
@Deprecated
274288
public static BeanPropertyMap construct(MapperConfig<?> config,
275289
Collection<SettableBeanProperty> props,
276290
Map<String,List<PropertyName>> aliasMapping) {

src/test/java/com/fasterxml/jackson/databind/misc/CaseInsensitiveDeserTest.java

+51-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.fasterxml.jackson.core.JsonProcessingException;
1010

1111
import com.fasterxml.jackson.databind.*;
12+
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
1213

1314
public class CaseInsensitiveDeserTest extends BaseMapTest
1415
{
@@ -93,13 +94,31 @@ public String getId() {
9394
}
9495
}
9596

97+
// [databind#1886]: allow case-insensitivity by default on a class
98+
@JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
99+
static class CaseInsensitiveRole {
100+
public String ID;
101+
public String Name;
102+
}
103+
104+
// [databind#1886]: allow case-insensitivity by default on a class
105+
static class CaseInsensitiveRoleContainer {
106+
public CaseInsensitiveRole role;
107+
}
108+
109+
// [databind#1886]: ... but also overrides
110+
static class CaseSensitiveRoleContainer {
111+
@JsonFormat(without={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
112+
public CaseInsensitiveRole role;
113+
}
114+
96115
/*
97116
/********************************************************
98117
/* Test methods
99118
/********************************************************
100119
*/
101120

102-
private final ObjectMapper MAPPER = new ObjectMapper();
121+
private final ObjectMapper MAPPER = newJsonMapper();
103122
private final ObjectMapper INSENSITIVE_MAPPER = jsonMapperBuilder()
104123
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
105124
.build();
@@ -158,7 +177,7 @@ public void testCreatorWithInsensitive() throws Exception
158177
}
159178

160179
// And allow config overrides too
161-
public void testCaseInsensitiveWithClassFormat() throws Exception
180+
public void testCaseInsensitiveViaConfigOverride() throws Exception
162181
{
163182
ObjectMapper mapper = new ObjectMapper();
164183
mapper.configOverride(Role.class)
@@ -181,4 +200,34 @@ public void testIssue1854() throws Exception
181200
assertNotNull(result.getItems());
182201
assertEquals(1, result.getItems().size());
183202
}
203+
204+
205+
// [databind#1886]: allow case-insensitivity by default on a class
206+
public void testCaseInsensitiveViaClassAnnotation() throws Exception
207+
{
208+
final String CONTAINED = aposToQuotes("{'role': {'id':'3','name':'Bob'}}");
209+
210+
// First: via wrapper/container:
211+
CaseInsensitiveRoleContainer cont = MAPPER.readValue(CONTAINED,
212+
CaseInsensitiveRoleContainer.class);
213+
assertEquals("3", cont.role.ID);
214+
assertEquals("Bob", cont.role.Name);
215+
216+
// second: directly as root value
217+
CaseInsensitiveRole role = MAPPER.readValue
218+
(aposToQuotes("{'id':'12','name':'Billy'}"),
219+
CaseInsensitiveRole.class);
220+
assertEquals("12", role.ID);
221+
assertEquals("Billy", role.Name);
222+
223+
// and finally, more complicated; should be possible to force sensitivity:
224+
try {
225+
/*CaseSensitiveRoleContainer r =*/ MAPPER.readValue(CONTAINED,
226+
CaseSensitiveRoleContainer.class);
227+
fail("Should not pass");
228+
} catch (UnrecognizedPropertyException e) {
229+
verifyException(e, "Unrecognized ");
230+
verifyException(e, "\"id\"");
231+
}
232+
}
184233
}

0 commit comments

Comments
 (0)