com.fasterxml.jackson.databind.PropertyNamingStrategies 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;
/**
* Container for standard {@link PropertyNamingStrategy} implementations
* and singleton instances.
*
* Added in Jackson 2.12 to resolve issue
* databind#2715.
*
* @since 2.12
*/
public abstract class PropertyNamingStrategies
implements java.io.Serializable
{
private static final long serialVersionUID = 2L;
/*
/**********************************************************************
/* Static instances that may be referenced
/**********************************************************************
*/
/**
* Naming convention used in Java, where words other than first are capitalized
* and no separator is used between words. Since this is the native Java naming convention,
* naming strategy will not do any transformation between names in data (JSON) and
* POJOS.
*
* Example external property names would be "numberValue", "namingStrategy", "theDefiniteProof".
*/
public static final PropertyNamingStrategy LOWER_CAMEL_CASE = LowerCamelCaseStrategy.INSTANCE;
/**
* Naming convention used in languages like Pascal, where all words are capitalized
* and no separator is used between words.
* See {@link UpperCamelCaseStrategy} for details.
*
* Example external property names would be "NumberValue", "NamingStrategy", "TheDefiniteProof".
*/
public static final PropertyNamingStrategy UPPER_CAMEL_CASE = UpperCamelCaseStrategy.INSTANCE;
/**
* Naming convention used in languages like C, where words are in lower-case
* letters, separated by underscores.
* See {@link SnakeCaseStrategy} for details.
*
* Example external property names would be "number_value", "naming_strategy", "the_definite_proof".
*/
public static final PropertyNamingStrategy SNAKE_CASE = SnakeCaseStrategy.INSTANCE;
/**
* Naming convention in which the words are in upper-case letters, separated by underscores.
* See {@link UpperSnakeCaseStrategy} for details.
* @since 2.13
*
*/
public static final PropertyNamingStrategy UPPER_SNAKE_CASE = UpperSnakeCaseStrategy.INSTANCE;
/**
* 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.
*
* Example external property names would be "numbervalue", "namingstrategy", "thedefiniteproof".
*/
public static final PropertyNamingStrategy LOWER_CASE = LowerCaseStrategy.INSTANCE;
/**
* Naming convention used in languages like Lisp, where words are in lower-case
* letters, separated by hyphens.
* See {@link KebabCaseStrategy} for details.
*
* Example external property names would be "number-value", "naming-strategy", "the-definite-proof".
*/
public static final PropertyNamingStrategy KEBAB_CASE = KebabCaseStrategy.INSTANCE;
/**
* Naming convention widely used as configuration properties name, where words are in
* lower-case letters, separated by dots.
* See {@link LowerDotCaseStrategy} for details.
*
* Example external property names would be "number.value", "naming.strategy", "the.definite.proof".
*/
public static final PropertyNamingStrategy LOWER_DOT_CASE = LowerDotCaseStrategy.INSTANCE;
/*
/**********************************************************************
/* Public base class for simple implementations
/**********************************************************************
*/
/**
* Intermediate base class for simple implementations
*/
public static abstract class NamingBase
extends PropertyNamingStrategy
{
private static final long serialVersionUID = 2L;
@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 String translateLowerCaseWithSeparator(final String input, final char separator)
{
if (input == null || input.isEmpty()) {
return input;
}
final int length = input.length();
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
/**********************************************************************
*/
/**
* 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.
*
*
- Every upper case letter in the Java property name is translated
* into two characters, an underscore and the lower case equivalent of the
* target character, with three exceptions.
*
- For contiguous sequences of upper case letters, characters after
* the first character are replaced only by their lower case equivalent,
* and are not preceded by an underscore.
*
- This provides for reasonable translations of upper case acronyms,
* e.g., "theWWW" is translated to "the_www".
* - An upper case character in the first position of the Java property
* name is not preceded by an underscore character, and is translated only
* to its lower case equivalent.
*
- For example, "Results" is translated to "results",
* and not to "_results".
* - An upper case character in the Java property name that is already
* preceded by an underscore character is translated only to its lower case
* equivalent, and is not preceded by an additional underscore.
*
- For example, "user_Name" is translated to
* "user_name", and not to "user__name" (with two
* underscore characters).
* - If the Java property name starts with an underscore, then that
* underscore is not included in the translated name, unless the Java
* property name is just one character in length, i.e., it is the
* underscore character. This applies only to the first character of the
* Java property name.
*
* These rules result in the following additional example translations from
* Java property names to JSON element names.
*
- "userName" is translated to "user_name"
* - "UserName" is translated to "user_name"
* - "USER_NAME" is translated to "user_name"
* - "user_name" is translated to "user_name" (unchanged)
* - "user" is translated to "user" (unchanged)
* - "User" is translated to "user"
* - "USER" is translated to "user"
* - "_user" is translated to "user"
* - "_User" is translated to "user"
* - "__user" is translated to "_user"
* (the first of two underscores was removed)
* - "user__name" is translated to "user__name"
* (unchanged, with two underscores)
*/
public static class SnakeCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.SnakeCaseStrategy INSTANCE
= new PropertyNamingStrategies.SnakeCaseStrategy();
@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;
}
}
/**
* A {@link PropertyNamingStrategy} that translates an input to the equivalent upper case snake
* case. The class extends {@link PropertyNamingStrategies.SnakeCaseStrategy} to retain the
* snake case conversion functionality offered by the strategy.
*
* @since 2.13
*/
public static class UpperSnakeCaseStrategy extends SnakeCaseStrategy
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.UpperSnakeCaseStrategy INSTANCE
= new PropertyNamingStrategies.UpperSnakeCaseStrategy();
@Override
public String translate(String input) {
String output = super.translate(input);
if (output == null) {
return null;
}
return output.toUpperCase();
}
}
/**
* "No-operation" strategy that is equivalent to not specifying any
* strategy: will simply return suggested standard bean naming as-is.
*/
public static class LowerCamelCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.LowerCamelCaseStrategy INSTANCE
= new PropertyNamingStrategies.LowerCamelCaseStrategy();
@Override
public String translate(String input) {
return input;
}
}
/**
* A {@link PropertyNamingStrategy} that translates typical camelCase Java
* property names to PascalCase JSON element names (i.e., with a capital
* first letter). In particular, the following translations are applied by
* this PropertyNamingStrategy.
*
* - The first lower-case letter in the Java property name is translated
* into its equivalent upper-case representation.
*
* This rules result in the following example translation from
* Java property names to JSON element names.
* - "userName" is translated to "UserName"
*/
public static class UpperCamelCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.UpperCamelCaseStrategy INSTANCE
= new PropertyNamingStrategies.UpperCamelCaseStrategy();
/**
* 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();
}
}
/**
* Simple strategy where external name simply only uses lower-case characters,
* and no separators.
* Conversion from internal name like "someOtherValue" would be into external name
* if "someothervalue".
*/
public static class LowerCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.LowerCaseStrategy INSTANCE
= new PropertyNamingStrategies.LowerCaseStrategy();
@Override
public String translate(String input) {
if (input == null || input.isEmpty()) {
return input;
}
return input.toLowerCase();
}
}
/**
* Naming strategy similar to {@link PropertyNamingStrategies.SnakeCaseStrategy},
* but instead of underscores
* as separators, uses hyphens. Naming convention traditionally used for languages
* like Lisp.
*/
public static class KebabCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.KebabCaseStrategy INSTANCE
= new PropertyNamingStrategies.KebabCaseStrategy();
@Override
public String translate(String input) {
return translateLowerCaseWithSeparator(input, '-');
}
}
/**
* Naming strategy similar to {@link PropertyNamingStrategies.KebabCaseStrategy},
* but instead of hyphens
* as separators, uses dots. Naming convention widely used as configuration properties name.
*/
public static class LowerDotCaseStrategy extends NamingBase
{
private static final long serialVersionUID = 2L;
/**
* @since 2.14
*/
public final static PropertyNamingStrategies.LowerDotCaseStrategy INSTANCE
= new PropertyNamingStrategies.LowerDotCaseStrategy();
@Override
public String translate(String input){
return translateLowerCaseWithSeparator(input, '.');
}
}
}