diff --git a/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java b/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java index 8426cf5a4c..316d49de5d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java +++ b/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java @@ -66,6 +66,13 @@ public class PropertyNamingStrategy */ public static final PropertyNamingStrategy KEBAB_CASE = new KebabCaseStrategy(); + /** + * Naming convention widely used as configuration properties name, where words are in + * lower-case letters, separated by dots. + * See {@link LowerCaseWithDotsStrategy} for details. + */ + public static final PropertyNamingStrategy LOWER_CASE_WITH_DOTS = new LowerCaseWithDotsStrategy(); + /* /********************************************************** /* API @@ -246,7 +253,8 @@ public static class SnakeCaseStrategy extends PropertyNamingStrategyBase @Override public String translate(String input) { - if (input == null) return input; // garbage in, garbage out + if (input == null) + return input; // garbage in, garbage out int length = input.length(); StringBuilder result = new StringBuilder(length * 2); int resultLength = 0; @@ -343,41 +351,58 @@ public String translate(String input) { public static class KebabCaseStrategy extends PropertyNamingStrategyBase { @Override - public String translate(String input) - { - if (input == null) return input; // garbage in, garbage out - int length = input.length(); - if (length == 0) { - return input; - } + public String translate(String input){ + return translateLowerCaseWithSeparator(input, '-'); + } + } - StringBuilder result = new StringBuilder(length + (length >> 1)); + /** + * Naming strategy similar to {@link KebabCaseStrategy}, but instead of hyphens + * as separators, uses dots. Naming convention widely used as configuration properties name. + */ + public static class LowerCaseWithDotsStrategy extends PropertyNamingStrategyBase { + @Override + public String translate(String input){ + return translateLowerCaseWithSeparator(input, '.'); + } + } - int upperCount = 0; + static String translateLowerCaseWithSeparator(String input, char separator){ + if (input == null) { + return input; // garbage in, garbage out + } - 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, '-'); - } - upperCount = 0; - } else { - // Otherwise starts new word, unless beginning of string - if ((upperCount == 0) && (i > 0)) { - result.append('-'); - } - ++upperCount; + int length = input.length(); + if (length == 0) { + return input; + } + + 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); } - result.append(lc); + ++upperCount; } - return result.toString(); + result.append(lc); } + return result.toString(); } } diff --git a/src/test/java/com/fasterxml/jackson/databind/introspect/TestNamingStrategyStd.java b/src/test/java/com/fasterxml/jackson/databind/introspect/TestNamingStrategyStd.java index 78944a0be2..ddbe651a6f 100644 --- a/src/test/java/com/fasterxml/jackson/databind/introspect/TestNamingStrategyStd.java +++ b/src/test/java/com/fasterxml/jackson/databind/introspect/TestNamingStrategyStd.java @@ -333,6 +333,40 @@ public void testSimpleKebabCase() throws Exception assertEquals("Billy", result.firstName); } + /* + /********************************************************** + /* Test methods for LOWER_CASE_WITH_DOTS + /********************************************************** + */ + + public void testLowerCaseWithDotsStrategyStandAlone() + { + assertEquals("some.value", + PropertyNamingStrategy.LOWER_CASE_WITH_DOTS.nameForField(null, null, "someValue")); + assertEquals("some.value", + PropertyNamingStrategy.LOWER_CASE_WITH_DOTS.nameForField(null, null, "SomeValue")); + assertEquals("url", + PropertyNamingStrategy.LOWER_CASE_WITH_DOTS.nameForField(null, null, "URL")); + assertEquals("url.stuff", + PropertyNamingStrategy.LOWER_CASE_WITH_DOTS.nameForField(null, null, "URLStuff")); + assertEquals("some.url.stuff", + PropertyNamingStrategy.LOWER_CASE_WITH_DOTS.nameForField(null, null, "SomeURLStuff")); + } + + public void testSimpleLowerCaseWithDots() throws Exception + { + final FirstNameBean input = new FirstNameBean("Bob"); + ObjectMapper m = jsonMapperBuilder() + .propertyNamingStrategy(PropertyNamingStrategy.LOWER_CASE_WITH_DOTS) + .build(); + + assertEquals(aposToQuotes("{'first.name':'Bob'}"), m.writeValueAsString(input)); + + FirstNameBean result = m.readValue(aposToQuotes("{'first.name':'Billy'}"), + FirstNameBean.class); + assertEquals("Billy", result.firstName); + } + /* /********************************************************** /* Test methods, other