com.fasterxml.jackson.databind.PropertyNamingStrategy Maven / Gradle / Ivy
package com.fasterxml.jackson.databind;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedField;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
import java.util.logging.Logger;
/**
* Class that defines how names of JSON properties ("external names")
* are derived from names of POJO methods and fields ("internal names"),
* in cases where no explicit annotations exist for naming.
* Methods are passed information about POJO member for which name is needed,
* as well as default name that would be used if no custom strategy was used.
*
* Default (empty) implementation returns suggested ("implicit" or "default") name unmodified
*
* Note that the strategy is guaranteed to be called once per logical property
* (which may be represented by multiple members; such as pair of a getter and
* a setter), but may be called for each: implementations should not count on
* exact number of times, and should work for any member that represent a
* property.
* Also note that calls are made during construction of serializers and deserializers
* which are typically cached, and not for every time serializer or deserializer
* is called.
*
* In absence of a registered custom strategy, the default Java property naming strategy
* is used, which leaves field names as is, and removes set/get/is prefix
* from methods (as well as lower-cases initial sequence of capitalized
* characters).
*
* NOTE! Since 2.12 sub-classes defined here (as well as static singleton instances thereof)
* are deprecated due to
* databind#2715.
* Please use constants and classes in {@link PropertyNamingStrategies} instead.
*
*/
@SuppressWarnings("serial")
public class PropertyNamingStrategy // NOTE: was abstract until 2.7
implements java.io.Serializable
{
private static final long serialVersionUID = 2L;
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#LOWER_CAMEL_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy LOWER_CAMEL_CASE = new PropertyNamingStrategy();
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#UPPER_CAMEL_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy UPPER_CAMEL_CASE = new UpperCamelCaseStrategy(false);
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#SNAKE_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy SNAKE_CASE = new SnakeCaseStrategy(false);
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#LOWER_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy LOWER_CASE = new LowerCaseStrategy(false);
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#KEBAB_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy KEBAB_CASE = new KebabCaseStrategy(false);
/**
* @deprecated Since 2.12 deprecated. Use {@link PropertyNamingStrategies#LOWER_DOT_CASE} instead.
* See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated // since 2.12
public static final PropertyNamingStrategy LOWER_DOT_CASE = new LowerDotCaseStrategy(false);
/*
/**********************************************************
/* API
/**********************************************************
*/
/**
* 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)
{
return defaultName;
}
/**
* Method called to find external name (name used in JSON) for given logical
* POJO property,
* 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)
{
return defaultName;
}
/**
* Method called to find external name (name used in JSON) for given logical
* 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)
{
return defaultName;
}
/**
* Method called to find external name (name used in JSON) for given logical
* 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
* @param ctorParam Constructor parameter used to pass property.
* @param defaultName Default name that would be used for property in absence of custom strategy
*/
public String nameForConstructorParameter(MapperConfig> config, AnnotatedParameter ctorParam,
String defaultName)
{
return defaultName;
}
/*
/**********************************************************
/* Public base class for simple implementations
/**********************************************************
*/
/**
* @deprecated Since 2.12 deprecated. See
* databind#2715
* for reasons for deprecation.
*/
@Deprecated
public static abstract class PropertyNamingStrategyBase extends PropertyNamingStrategy
{
protected PropertyNamingStrategyBase() {
// For use via annotations: WARN
this(true);
}
protected PropertyNamingStrategyBase(boolean logWarning) {
super();
if (logWarning) {
final String simple = getClass().getSimpleName();
Logger.getLogger(getClass().getName())
.warning(
"PropertyNamingStrategy."+simple+" is used but it has been deprecated due to " +
"risk of deadlock. Consider using PropertyNamingStrategies."+simple+" instead. " +
"See https://github.com/FasterXML/jackson-databind/issues/2715 for more details.");
}
}
@Override
public String nameForField(MapperConfig> config, AnnotatedField field, String defaultName)
{
return translate(defaultName);
}
@Override
public String nameForGetterMethod(MapperConfig> config, AnnotatedMethod method, String defaultName)
{
return translate(defaultName);
}
@Override
public String nameForSetterMethod(MapperConfig> config, AnnotatedMethod method, String defaultName)
{
return translate(defaultName);
}
@Override
public String nameForConstructorParameter(MapperConfig> config, AnnotatedParameter ctorParam,
String defaultName)
{
return translate(defaultName);
}
public abstract String translate(String propertyName);
/**
* Helper method to share implementation between snake and dotted case.
*/
protected static String translateLowerCaseWithSeparator(final String input, final char separator)
{
if (input == null) {
return input; // garbage in, garbage out
}
final int length = input.length();
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
if (upperCount > 1) {
// so insert hyphen before the last character now
result.insert(result.length() - 1, separator);
}
upperCount = 0;
} else {
// Otherwise starts new word, unless beginning of string
if ((upperCount == 0) && (i > 0)) {
result.append(separator);
}
++upperCount;
}
result.append(lc);
}
return result.toString();
}
}
/*
/**********************************************************
/* Standard implementations
/**********************************************************
*/
/**
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.SnakeCaseStrategy} instead
* (see
* databind#2715
* for reason for deprecation)
*/
@Deprecated // since 2.12
public static class SnakeCaseStrategy extends PropertyNamingStrategyBase
{
public SnakeCaseStrategy() { }
protected SnakeCaseStrategy(boolean logWarning) { super(logWarning); }
@Override
public String translate(String input)
{
if (input == null) return input; // garbage in, garbage out
int length = input.length();
StringBuilder result = new StringBuilder(length * 2);
int resultLength = 0;
boolean wasPrevTranslated = false;
for (int i = 0; i < length; i++)
{
char c = input.charAt(i);
if (i > 0 || c != '_') // skip first starting underscore
{
if (Character.isUpperCase(c))
{
if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_')
{
result.append('_');
resultLength++;
}
c = Character.toLowerCase(c);
wasPrevTranslated = true;
}
else
{
wasPrevTranslated = false;
}
result.append(c);
resultLength++;
}
}
return resultLength > 0 ? result.toString() : input;
}
}
/**
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.UpperCamelCaseStrategy} instead
* (see
* databind#2715
* for reason for deprecation)
*/
@Deprecated // since 2.12
public static class UpperCamelCaseStrategy extends PropertyNamingStrategyBase
{
public UpperCamelCaseStrategy() { }
protected UpperCamelCaseStrategy(boolean logWarning) { super(logWarning); }
/**
* Converts camelCase to PascalCase
*
* For example, "userName" would be converted to "UserName".
*
* @param input formatted as camelCase string
* @return input converted to PascalCase format
*/
@Override
public String translate(String input) {
if (input == null || input.isEmpty()){
return input; // garbage in, garbage out
}
// Replace first lower-case letter with upper-case equivalent
char c = input.charAt(0);
char uc = Character.toUpperCase(c);
if (c == uc) {
return input;
}
StringBuilder sb = new StringBuilder(input);
sb.setCharAt(0, uc);
return sb.toString();
}
}
/**
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.LowerCaseStrategy} instead
* (see
* databind#2715
* for reason for deprecation)
*/
@Deprecated // since 2.12
public static class LowerCaseStrategy extends PropertyNamingStrategyBase
{
public LowerCaseStrategy() { }
protected LowerCaseStrategy(boolean logWarning) { super(logWarning); }
@Override
public String translate(String input) {
return input.toLowerCase();
}
}
/**
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.KebabCaseStrategy} instead
* (see
* databind#2715
* for reason for deprecation)
*/
@Deprecated // since 2.12
public static class KebabCaseStrategy extends PropertyNamingStrategyBase
{
public KebabCaseStrategy() { }
protected KebabCaseStrategy(boolean logWarning) { super(logWarning); }
@Override
public String translate(String input) {
return translateLowerCaseWithSeparator(input, '-');
}
}
/**
* @deprecated Since 2.12 use {@link PropertyNamingStrategies.LowerDotCaseStrategy} instead
* (see
* databind#2715
* for reason for deprecation)
*/
@Deprecated // since 2.12
public static class LowerDotCaseStrategy extends PropertyNamingStrategyBase
{
public LowerDotCaseStrategy() { }
protected LowerDotCaseStrategy(boolean logWarning) { super(logWarning); }
@Override
public String translate(String input){
return translateLowerCaseWithSeparator(input, '.');
}
}
}