Skip to content

Commit 2b30eab

Browse files
committed
Fix #953 (partial wrt i/I problem)
1 parent b1a8293 commit 2b30eab

File tree

4 files changed

+54
-12
lines changed

4 files changed

+54
-12
lines changed

release-notes/CREDITS-2.x

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,3 +1031,7 @@ Joseph Koshakow (jkosh44@github)
10311031
* Contributed fix for #2515: `ObjectMapper.registerSubtypes(NamedType...)` doesn't allow registering
10321032
the same POJO for two different type ids
10331033
(2.11.0)
1034+
1035+
Máté Rédecsi (rmatesz@github)
1036+
* Reported #953: i-I case convertion problem in Turkish locale with case-insensitive deserialization
1037+
(2.11.0)

release-notes/VERSION-2.x

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Project: jackson-databind
66

77
2.11.0 (not yet released)
88

9+
#953: i-I case convertion problem in Turkish locale with case-insensitive deserialization
10+
(reported by Máté R)
911
#2049: TreeTraversingParser and UTF8StreamJsonParser create contexts differently
1012
(reported by Antonio P)
1113
#2352: Support use of `@JsonAlias` for enum values

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,7 @@ public JsonDeserializer<?> build()
348348
{
349349
Collection<SettableBeanProperty> props = _properties.values();
350350
_fixAccess(props);
351-
BeanPropertyMap propertyMap = BeanPropertyMap.construct(props,
352-
_config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES),
351+
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
353352
_collectAliases(props));
354353
propertyMap.assignIndexes();
355354

@@ -425,8 +424,7 @@ public JsonDeserializer<?> buildBuilderBased(JavaType valueType, String expBuild
425424
// And if so, we can try building the deserializer
426425
Collection<SettableBeanProperty> props = _properties.values();
427426
_fixAccess(props);
428-
BeanPropertyMap propertyMap = BeanPropertyMap.construct(props,
429-
_config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES),
427+
BeanPropertyMap propertyMap = BeanPropertyMap.construct(_config, props,
430428
_collectAliases(props));
431429
propertyMap.assignIndexes();
432430

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

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
import com.fasterxml.jackson.databind.DeserializationFeature;
1111
import com.fasterxml.jackson.databind.JsonDeserializer;
1212
import com.fasterxml.jackson.databind.JsonMappingException;
13+
import com.fasterxml.jackson.databind.MapperFeature;
1314
import com.fasterxml.jackson.databind.PropertyName;
15+
import com.fasterxml.jackson.databind.cfg.MapperConfig;
1416
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
1517
import com.fasterxml.jackson.databind.util.ClassUtil;
1618
import com.fasterxml.jackson.databind.util.NameTransformer;
@@ -77,18 +79,38 @@ public class BeanPropertyMap
7779
private final Map<String,String> _aliasMapping;
7880

7981
/**
80-
* @since 2.9
82+
* We require {@link Locale} since case changes are locale-sensitive in certain
83+
* cases (see <a href="https://en.wikipedia.org/wiki/Dotted_and_dotless_I">Turkish I</a>
84+
* for example)
85+
*
86+
* @since 2.11
87+
*/
88+
private final Locale _locale;
89+
90+
/**
91+
* @since 2.11
8192
*/
8293
public BeanPropertyMap(boolean caseInsensitive, Collection<SettableBeanProperty> props,
83-
Map<String,List<PropertyName>> aliasDefs)
94+
Map<String,List<PropertyName>> aliasDefs,
95+
Locale locale)
8496
{
8597
_caseInsensitive = caseInsensitive;
8698
_propsInOrder = props.toArray(new SettableBeanProperty[props.size()]);
8799
_aliasDefs = aliasDefs;
88100
_aliasMapping = _buildAliasMapping(aliasDefs);
101+
_locale = locale;
89102
init(props);
90103
}
91104

105+
/**
106+
* @deprecated since 2.11
107+
*/
108+
@Deprecated
109+
public BeanPropertyMap(boolean caseInsensitive, Collection<SettableBeanProperty> props,
110+
Map<String,List<PropertyName>> aliasDefs) {
111+
this(caseInsensitive, props, aliasDefs, Locale.getDefault());
112+
}
113+
92114
/* Copy constructors used when a property can replace existing one
93115
*
94116
* @since 2.9.6
@@ -98,6 +120,7 @@ private BeanPropertyMap(BeanPropertyMap src,
98120
{
99121
// First, copy most fields as is:
100122
_caseInsensitive = src._caseInsensitive;
123+
_locale = src._locale;
101124
_hashMask = src._hashMask;
102125
_size = src._size;
103126
_spillCount = src._spillCount;
@@ -120,6 +143,7 @@ private BeanPropertyMap(BeanPropertyMap src,
120143
{
121144
// First, copy most fields as is:
122145
_caseInsensitive = src._caseInsensitive;
146+
_locale = src._locale;
123147
_hashMask = src._hashMask;
124148
_size = src._size;
125149
_spillCount = src._spillCount;
@@ -156,7 +180,8 @@ private BeanPropertyMap(BeanPropertyMap src,
156180
@Deprecated // since 2.8
157181
public BeanPropertyMap(boolean caseInsensitive, Collection<SettableBeanProperty> props)
158182
{
159-
this(caseInsensitive, props, Collections.<String,List<PropertyName>>emptyMap());
183+
this(caseInsensitive, props, Collections.<String,List<PropertyName>>emptyMap(),
184+
Locale.getDefault());
160185
}
161186

162187
/**
@@ -165,6 +190,7 @@ public BeanPropertyMap(boolean caseInsensitive, Collection<SettableBeanProperty>
165190
protected BeanPropertyMap(BeanPropertyMap base, boolean caseInsensitive)
166191
{
167192
_caseInsensitive = caseInsensitive;
193+
_locale = base._locale;
168194
_aliasDefs = base._aliasDefs;
169195
_aliasMapping = base._aliasMapping;
170196

@@ -247,10 +273,22 @@ private final static int findSize(int size)
247273
}
248274
return result;
249275
}
250-
276+
277+
/**
278+
* @since 2.11
279+
*/
280+
public static BeanPropertyMap construct(MapperConfig<?> config,
281+
Collection<SettableBeanProperty> props,
282+
Map<String,List<PropertyName>> aliasMapping) {
283+
return new BeanPropertyMap(config.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES),
284+
props, aliasMapping,
285+
config.getLocale());
286+
}
287+
251288
/**
252-
* @since 2.6
289+
* @deprecated since 2.11
253290
*/
291+
@Deprecated
254292
public static BeanPropertyMap construct(Collection<SettableBeanProperty> props,
255293
boolean caseInsensitive, Map<String,List<PropertyName>> aliasMapping) {
256294
return new BeanPropertyMap(caseInsensitive, props, aliasMapping);
@@ -490,7 +528,7 @@ public SettableBeanProperty[] getPropertiesInInsertionOrder() {
490528
// Confining this case insensitivity to this function (and the find method) in case we want to
491529
// apply a particular locale to the lower case function. For now, using the default.
492530
protected final String getPropertyName(SettableBeanProperty prop) {
493-
return _caseInsensitive ? prop.getName().toLowerCase() : prop.getName();
531+
return _caseInsensitive ? prop.getName().toLowerCase(_locale) : prop.getName();
494532
}
495533

496534
/*
@@ -521,7 +559,7 @@ public SettableBeanProperty find(String key)
521559
throw new IllegalArgumentException("Cannot pass null property name");
522560
}
523561
if (_caseInsensitive) {
524-
key = key.toLowerCase();
562+
key = key.toLowerCase(_locale);
525563
}
526564

527565
// inlined `_hashCode(key)`
@@ -779,7 +817,7 @@ private Map<String,String> _buildAliasMapping(Map<String,List<PropertyName>> def
779817
for (Map.Entry<String,List<PropertyName>> entry : defs.entrySet()) {
780818
String key = entry.getKey();
781819
if (_caseInsensitive) {
782-
key = key.toLowerCase();
820+
key = key.toLowerCase(_locale);
783821
}
784822
for (PropertyName pn : entry.getValue()) {
785823
String mapped = pn.getSimpleName();

0 commit comments

Comments
 (0)