From da9e0d14a5e63225013b6054af0e152069d5be24 Mon Sep 17 00:00:00 2001 From: saviukd Date: Wed, 27 Nov 2019 17:06:13 +0100 Subject: [PATCH 1/2] Use locale passed to ObjectMapper configuration everywhere. Allows to fix turkish i parsing https://github.com/FasterXML/jackson-databind/issues/953#event-813678035 --- .../jackson/databind/ObjectMapper.java | 5 +- .../databind/PropertyNamingStrategy.java | 138 +++++++++--------- .../deser/BeanDeserializerBuilder.java | 7 +- .../deser/BeanDeserializerFactory.java | 4 +- .../databind/deser/impl/BeanPropertyMap.java | 43 +++--- .../deser/impl/PropertyBasedCreator.java | 11 +- .../introspect/BasicClassIntrospector.java | 10 +- .../introspect/POJOPropertiesCollector.java | 17 ++- .../jsonFormatVisitors/JsonFormatTypes.java | 1 + .../jackson/databind/ObjectMapperTest.java | 36 +++++ .../POJOPropertiesCollectorTest.java | 2 +- .../introspect/TestBuilderMethods.java | 3 +- .../introspect/TestNamingStrategyCustom.java | 14 +- .../introspect/TestNamingStrategyStd.java | 35 ++--- .../databind/misc/BeanPropertyMapTest.java | 2 +- 15 files changed, 196 insertions(+), 132 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index bb7ccc7166..ffaf955236 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -393,6 +393,8 @@ public boolean useForType(JavaType t) */ protected final ConfigOverrides _configOverrides; + private Locale _locale = Locale.getDefault(); + /* /********************************************************** /* Configuration settings: mix-in annotations @@ -639,7 +641,7 @@ public ObjectMapper(JsonFactory jf, * @since 2.5 */ protected ClassIntrospector defaultClassIntrospector() { - return new BasicClassIntrospector(); + return new BasicClassIntrospector(_locale); } /* @@ -2085,6 +2087,7 @@ public InjectableValues getInjectableValues() { * Default value used is {@link Locale#getDefault()}. */ public ObjectMapper setLocale(Locale l) { + _locale = l; _deserializationConfig = _deserializationConfig.with(l); _serializationConfig = _serializationConfig.with(l); return this; diff --git a/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java b/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java index 0b5563be1f..8f1384ac04 100644 --- a/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java +++ b/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.databind.introspect.AnnotatedMethod; import com.fasterxml.jackson.databind.introspect.AnnotatedParameter; +import java.util.Locale; + /** * Class that defines how names of JSON properties ("external names") * are derived from names of POJO methods and fields ("internal names"), @@ -57,12 +59,12 @@ public class PropertyNamingStrategy // NOTE: was abstract until 2.7 * @since 2.7 (was formerly called {@link #PASCAL_CASE_TO_CAMEL_CASE}) */ public static final PropertyNamingStrategy LOWER_CAMEL_CASE = new PropertyNamingStrategy(); - + /** * Naming convention in which all words of the logical name are in lower case, and * no separator is used between words. * See {@link LowerCaseStrategy} for details. - * + * * @since 2.4 */ public static final PropertyNamingStrategy LOWER_CASE = new LowerCaseStrategy(); @@ -71,7 +73,7 @@ public class PropertyNamingStrategy // NOTE: was abstract until 2.7 * Naming convention used in languages like Lisp, where words are in lower-case * letters, separated by hyphens. * See {@link KebabCaseStrategy} for details. - * + * * @since 2.7 */ public static final PropertyNamingStrategy KEBAB_CASE = new KebabCaseStrategy(); @@ -95,17 +97,17 @@ public class PropertyNamingStrategy // NOTE: was abstract until 2.7 * Method called to find external name (name used in JSON) for given logical * POJO property, * as defined by given field. - * + * * @param config Configuration in used: either SerializationConfig * or DeserializationConfig, depending on whether method is called * during serialization or deserialization * @param field Field used to access property * @param defaultName Default name that would be used for property in absence of custom strategy - * + * * @return Logical name to use for property that the field represents */ public String nameForField(MapperConfig config, AnnotatedField field, - String defaultName) + String defaultName, Locale locale) { return defaultName; } @@ -116,17 +118,17 @@ public String nameForField(MapperConfig config, AnnotatedField field, * as defined by given getter method; typically called when building a serializer. * (but not always -- when using "getter-as-setter", may be called during * deserialization) - * + * * @param config Configuration in used: either SerializationConfig * or DeserializationConfig, depending on whether method is called * during serialization or deserialization * @param method Method used to access property. * @param defaultName Default name that would be used for property in absence of custom strategy - * + * * @return Logical name to use for property that the method represents */ public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, - String defaultName) + String defaultName, Locale locale) { return defaultName; } @@ -136,17 +138,17 @@ public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method * POJO property, * as defined by given setter method; typically called when building a deserializer * (but not necessarily only then). - * + * * @param config Configuration in used: either SerializationConfig * or DeserializationConfig, depending on whether method is called * during serialization or deserialization * @param method Method used to access property. * @param defaultName Default name that would be used for property in absence of custom strategy - * + * * @return Logical name to use for property that the method represents */ public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, - String defaultName) + String defaultName, Locale locale) { return defaultName; } @@ -156,7 +158,7 @@ public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method * POJO property, * as defined by given constructor parameter; typically called when building a deserializer * (but not necessarily only then). - * + * * @param config Configuration in used: either SerializationConfig * or DeserializationConfig, depending on whether method is called * during serialization or deserialization @@ -164,7 +166,7 @@ public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method * @param defaultName Default name that would be used for property in absence of custom strategy */ public String nameForConstructorParameter(MapperConfig config, AnnotatedParameter ctorParam, - String defaultName) + String defaultName, Locale locale) { return defaultName; } @@ -174,35 +176,35 @@ public String nameForConstructorParameter(MapperConfig config, AnnotatedParam /* Public base class for simple implementations /********************************************************** */ - + public static abstract class PropertyNamingStrategyBase extends PropertyNamingStrategy { @Override - public String nameForField(MapperConfig config, AnnotatedField field, String defaultName) + public String nameForField(MapperConfig config, AnnotatedField field, String defaultName, Locale locale) { - return translate(defaultName); + return translate(defaultName, locale); } @Override - public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) + public String nameForGetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName, Locale locale) { - return translate(defaultName); + return translate(defaultName, locale); } @Override - public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName) + public String nameForSetterMethod(MapperConfig config, AnnotatedMethod method, String defaultName,Locale locale) { - return translate(defaultName); + return translate(defaultName, locale); } @Override public String nameForConstructorParameter(MapperConfig config, AnnotatedParameter ctorParam, - String defaultName) + String defaultName, Locale locale) { - return translate(defaultName); + return translate(defaultName, locale); } - - public abstract String translate(String propertyName); + + public abstract String translate(String propertyName, Locale locale); /** * Helper method to share implementation between snake and dotted case. @@ -216,13 +218,13 @@ protected static String translateLowerCaseWithSeparator(final String input, fina if (length == 0) { return input; } - + final StringBuilder result = new StringBuilder(length + (length >> 1)); int upperCount = 0; for (int i = 0; i < length; ++i) { char ch = input.charAt(i); char lc = Character.toLowerCase(ch); - + if (lc == ch) { // lower-case letter means we can get new word // but need to check for multi-letter upper-case (acronym), where assumption // is that the last upper-case char is start of a new word @@ -249,41 +251,41 @@ protected static String translateLowerCaseWithSeparator(final String input, fina /* Standard implementations /********************************************************** */ - + /** - * A {@link PropertyNamingStrategy} that translates typical camel case Java - * property names to lower case JSON element names, separated by - * underscores. This implementation is somewhat lenient, in that it - * provides some additional translations beyond strictly translating from - * camel case only. In particular, the following translations are applied + * A {@link PropertyNamingStrategy} that translates typical camel case Java + * property names to lower case JSON element names, separated by + * underscores. This implementation is somewhat lenient, in that it + * provides some additional translations beyond strictly translating from + * camel case only. In particular, the following translations are applied * by this PropertyNamingStrategy. - * - *