Skip to content

Commit b198684

Browse files
committed
Merge branch '2.12'
2 parents f7d4bff + d051497 commit b198684

File tree

5 files changed

+95
-46
lines changed

5 files changed

+95
-46
lines changed

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
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

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.*;
44

5+
import com.fasterxml.jackson.annotation.JsonFormat;
56
import com.fasterxml.jackson.databind.*;
67
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
78
import com.fasterxml.jackson.databind.deser.impl.BeanPropertyMap;
@@ -353,25 +354,9 @@ public JsonDeserializer<?> build()
353354
props = _addIdProp(_properties,
354355
new ObjectIdValueProperty(_objectIdReader, PropertyMetadata.STD_REQUIRED));
355356
}
356-
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
357-
_collectAliases(props));
358-
359-
// view processing must be enabled if:
360-
// (a) fields are not included by default (when deserializing with view), OR
361-
// (b) one of properties has view(s) to included in defined
362-
boolean anyViews = !_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION);
363-
if (!anyViews) {
364-
for (SettableBeanProperty prop : props) {
365-
if (prop.hasViews()) {
366-
anyViews = true;
367-
break;
368-
}
369-
}
370-
}
371-
372-
return new BeanDeserializer(this,
373-
_beanDesc, propertyMap, _backRefProperties, _ignorableProps, _ignoreAllUnknown,
374-
anyViews);
357+
return new BeanDeserializer(this, _beanDesc,
358+
_constructPropMap(props), _backRefProperties, _ignorableProps, _ignoreAllUnknown,
359+
_anyViews(props));
375360
}
376361

377362
/**
@@ -424,21 +409,8 @@ public JsonDeserializer<?> buildBuilderBased(JavaType valueType, String expBuild
424409
} else {
425410
props = _properties.values();
426411
}
427-
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
428-
_collectAliases(props));
429-
430-
boolean anyViews = !_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION);
431-
432-
if (!anyViews) {
433-
for (SettableBeanProperty prop : props) {
434-
if (prop.hasViews()) {
435-
anyViews = true;
436-
break;
437-
}
438-
}
439-
}
440-
441-
return createBuilderBasedDeserializer(valueType, propertyMap, anyViews);
412+
return createBuilderBasedDeserializer(valueType, _constructPropMap(props),
413+
_anyViews(props));
442414
}
443415

444416
/**
@@ -516,7 +488,37 @@ protected Collection<SettableBeanProperty> _addIdProp(Map<String, SettableBeanPr
516488
}
517489
return result;
518490
}
519-
491+
492+
protected boolean _anyViews(Collection<SettableBeanProperty> props)
493+
{
494+
// view processing must be enabled if:
495+
// (a) fields are not included by default (when deserializing with view), OR
496+
// (b) one of properties has view(s) to included in defined
497+
if (!_config.isEnabled(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
498+
return true;
499+
}
500+
for (SettableBeanProperty prop : props) {
501+
if (prop.hasViews()) {
502+
return true;
503+
}
504+
}
505+
return false;
506+
}
507+
508+
protected BeanPropertyMap _constructPropMap(Collection<SettableBeanProperty> props)
509+
{
510+
// 07-May-2020, tatu: First find combination of per-type config overrides (higher
511+
// precedence) and per-type annotations (lower):
512+
JsonFormat.Value format = _beanDesc.findExpectedFormat(null);
513+
// and see if any of those has explicit definition; if not, use global baseline default
514+
Boolean B = format.getFeature(JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES);
515+
boolean caseInsensitive = (B == null)
516+
? _config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
517+
: B.booleanValue();
518+
519+
return BeanPropertyMap.construct(_config, props, _collectAliases(props), caseInsensitive);
520+
}
521+
520522
protected PropertyName[][] _collectAliases(Collection<SettableBeanProperty> props)
521523
{
522524
PropertyName[][] result = null;

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import com.fasterxml.jackson.core.sym.FieldNameMatcher;
77
import com.fasterxml.jackson.core.util.InternCache;
88
import com.fasterxml.jackson.core.util.Named;
9+
910
import com.fasterxml.jackson.databind.DeserializationContext;
1011
import com.fasterxml.jackson.databind.JsonDeserializer;
11-
import com.fasterxml.jackson.databind.MapperFeature;
1212
import com.fasterxml.jackson.databind.PropertyName;
1313
import com.fasterxml.jackson.databind.cfg.MapperConfig;
1414
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
@@ -111,12 +111,11 @@ protected BeanPropertyMap(BeanPropertyMap base, boolean caseInsensitive)
111111

112112
public static BeanPropertyMap construct(MapperConfig<?> config,
113113
Collection<SettableBeanProperty> props,
114-
PropertyName[][] aliases)
114+
PropertyName[][] aliases,
115+
boolean caseInsensitive)
115116
{
116117
return new BeanPropertyMap(props, aliases,
117-
config.getLocale(),
118-
config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES),
119-
true);
118+
config.getLocale(), caseInsensitive, true);
120119
}
121120

122121
/*

src/test/java/com/fasterxml/jackson/databind/ObjectReaderValueOfWithValueTypeTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ public void testValueOfJsonNodeWithValueType() throws IOException {
124124

125125
@Test
126126
public void testValueOfReaderWithValueType() throws IOException {
127-
when(objectReader.forType((Class) any())).thenReturn(objectReader);
127+
when(objectReader.forType((Class<?>) any())).thenReturn(objectReader);
128128
when(objectReader.readValue((Reader) any())).thenReturn(pojo);
129-
when(objectReader.readValue((Reader) any(), (Class) any())).thenCallRealMethod();
129+
when(objectReader.readValue((Reader) any(), (Class<?>) any())).thenCallRealMethod();
130130

131131
Reader source = new StringReader("{}");
132132
POJO result = objectReader.readValue(source, POJO.class);

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

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import com.fasterxml.jackson.annotation.JsonFormat;
77
import com.fasterxml.jackson.annotation.JsonProperty;
88

9-
import com.fasterxml.jackson.core.JsonProcessingException;
10-
119
import com.fasterxml.jackson.databind.*;
1210
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
1311

@@ -94,13 +92,31 @@ public String getId() {
9492
}
9593
}
9694

95+
// [databind#1886]: allow case-insensitivity by default on a class
96+
@JsonFormat(with={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
97+
static class CaseInsensitiveRole {
98+
public String ID;
99+
public String Name;
100+
}
101+
102+
// [databind#1886]: allow case-insensitivity by default on a class
103+
static class CaseInsensitiveRoleContainer {
104+
public CaseInsensitiveRole role;
105+
}
106+
107+
// [databind#1886]: ... but also overrides
108+
static class CaseSensitiveRoleContainer {
109+
@JsonFormat(without={ JsonFormat.Feature.ACCEPT_CASE_INSENSITIVE_PROPERTIES })
110+
public CaseInsensitiveRole role;
111+
}
112+
97113
/*
98114
/********************************************************
99115
/* Test methods
100116
/********************************************************
101117
*/
118+
private final ObjectMapper MAPPER = newJsonMapper();
102119

103-
private final ObjectMapper MAPPER = objectMapper();
104120
private final ObjectMapper INSENSITIVE_MAPPER = jsonMapperBuilder()
105121
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
106122
.build();
@@ -159,7 +175,7 @@ public void testCreatorWithInsensitive() throws Exception
159175
}
160176

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

0 commit comments

Comments
 (0)