Fix FieldNamingPolicy.upperCaseFirstLetter
uppercasing non-letter (#2004)
This commit is contained in:
parent
466ca72916
commit
b3188c1132
|
@ -71,7 +71,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy {
|
||||||
*/
|
*/
|
||||||
UPPER_CAMEL_CASE_WITH_SPACES() {
|
UPPER_CAMEL_CASE_WITH_SPACES() {
|
||||||
@Override public String translateName(Field f) {
|
@Override public String translateName(Field f) {
|
||||||
return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
|
return upperCaseFirstLetter(separateCamelCase(f.getName(), ' '));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy {
|
||||||
*/
|
*/
|
||||||
LOWER_CASE_WITH_UNDERSCORES() {
|
LOWER_CASE_WITH_UNDERSCORES() {
|
||||||
@Override public String translateName(Field f) {
|
@Override public String translateName(Field f) {
|
||||||
return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH);
|
return separateCamelCase(f.getName(), '_').toLowerCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy {
|
||||||
*/
|
*/
|
||||||
LOWER_CASE_WITH_DASHES() {
|
LOWER_CASE_WITH_DASHES() {
|
||||||
@Override public String translateName(Field f) {
|
@Override public String translateName(Field f) {
|
||||||
return separateCamelCase(f.getName(), "-").toLowerCase(Locale.ENGLISH);
|
return separateCamelCase(f.getName(), '-').toLowerCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -135,15 +135,15 @@ public enum FieldNamingPolicy implements FieldNamingStrategy {
|
||||||
*/
|
*/
|
||||||
LOWER_CASE_WITH_DOTS() {
|
LOWER_CASE_WITH_DOTS() {
|
||||||
@Override public String translateName(Field f) {
|
@Override public String translateName(Field f) {
|
||||||
return separateCamelCase(f.getName(), ".").toLowerCase(Locale.ENGLISH);
|
return separateCamelCase(f.getName(), '.').toLowerCase(Locale.ENGLISH);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the field name that uses camel-case define word separation into
|
* Converts the field name that uses camel-case define word separation into
|
||||||
* separate words that are separated by the provided {@code separatorString}.
|
* separate words that are separated by the provided {@code separator}.
|
||||||
*/
|
*/
|
||||||
static String separateCamelCase(String name, String separator) {
|
static String separateCamelCase(String name, char separator) {
|
||||||
StringBuilder translation = new StringBuilder();
|
StringBuilder translation = new StringBuilder();
|
||||||
for (int i = 0, length = name.length(); i < length; i++) {
|
for (int i = 0, length = name.length(); i < length; i++) {
|
||||||
char character = name.charAt(i);
|
char character = name.charAt(i);
|
||||||
|
@ -158,21 +158,25 @@ public enum FieldNamingPolicy implements FieldNamingStrategy {
|
||||||
/**
|
/**
|
||||||
* Ensures the JSON field names begins with an upper case letter.
|
* Ensures the JSON field names begins with an upper case letter.
|
||||||
*/
|
*/
|
||||||
static String upperCaseFirstLetter(String name) {
|
static String upperCaseFirstLetter(String s) {
|
||||||
int firstLetterIndex = 0;
|
int length = s.length();
|
||||||
int limit = name.length() - 1;
|
for (int i = 0; i < length; i++) {
|
||||||
for(; !Character.isLetter(name.charAt(firstLetterIndex)) && firstLetterIndex < limit; ++firstLetterIndex);
|
char c = s.charAt(i);
|
||||||
|
if (Character.isLetter(c)) {
|
||||||
|
if (Character.isUpperCase(c)) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
char firstLetter = name.charAt(firstLetterIndex);
|
char uppercased = Character.toUpperCase(c);
|
||||||
if(Character.isUpperCase(firstLetter)) { //The letter is already uppercased, return the original
|
// For leading letter only need one substring
|
||||||
return name;
|
if (i == 0) {
|
||||||
|
return uppercased + s.substring(1);
|
||||||
|
} else {
|
||||||
|
return s.substring(0, i) + uppercased + s.substring(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char uppercased = Character.toUpperCase(firstLetter);
|
return s;
|
||||||
if(firstLetterIndex == 0) { //First character in the string is the first letter, saves 1 substring
|
|
||||||
return uppercased + name.substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name.substring(0, firstLetterIndex) + uppercased + name.substring(firstLetterIndex + 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
130
gson/src/test/java/com/google/gson/FieldNamingPolicyTest.java
Normal file
130
gson/src/test/java/com/google/gson/FieldNamingPolicyTest.java
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
package com.google.gson;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.Locale;
|
||||||
|
import org.junit.Test;
|
||||||
|
import com.google.gson.functional.FieldNamingTest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs tests directly against {@link FieldNamingPolicy}; for integration tests
|
||||||
|
* see {@link FieldNamingTest}.
|
||||||
|
*/
|
||||||
|
public class FieldNamingPolicyTest {
|
||||||
|
@Test
|
||||||
|
public void testSeparateCamelCase() {
|
||||||
|
// Map from original -> expected
|
||||||
|
String[][] argumentPairs = {
|
||||||
|
{ "a", "a" },
|
||||||
|
{ "ab", "ab" },
|
||||||
|
{ "Ab", "Ab" },
|
||||||
|
{ "aB", "a_B" },
|
||||||
|
{ "AB", "A_B" },
|
||||||
|
{ "A_B", "A__B" },
|
||||||
|
{ "firstSecondThird", "first_Second_Third" },
|
||||||
|
{ "__", "__" },
|
||||||
|
{ "_123", "_123" }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String[] pair : argumentPairs) {
|
||||||
|
assertEquals(pair[1], FieldNamingPolicy.separateCamelCase(pair[0], '_'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpperCaseFirstLetter() {
|
||||||
|
// Map from original -> expected
|
||||||
|
String[][] argumentPairs = {
|
||||||
|
{ "a", "A" },
|
||||||
|
{ "ab", "Ab" },
|
||||||
|
{ "AB", "AB" },
|
||||||
|
{ "_a", "_A" },
|
||||||
|
{ "_ab", "_Ab" },
|
||||||
|
{ "__", "__" },
|
||||||
|
{ "_1", "_1" },
|
||||||
|
// Not a letter, but has uppercase variant (should not be uppercased)
|
||||||
|
// See https://github.com/google/gson/issues/1965
|
||||||
|
{ "\u2170", "\u2170" },
|
||||||
|
{ "_\u2170", "_\u2170" },
|
||||||
|
{ "\u2170a", "\u2170A" },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (String[] pair : argumentPairs) {
|
||||||
|
assertEquals(pair[1], FieldNamingPolicy.upperCaseFirstLetter(pair[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upper casing policies should be unaffected by default Locale.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUpperCasingLocaleIndependent() throws Exception {
|
||||||
|
class Dummy {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
int i;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldNamingPolicy[] policies = {
|
||||||
|
FieldNamingPolicy.UPPER_CAMEL_CASE,
|
||||||
|
FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES
|
||||||
|
};
|
||||||
|
|
||||||
|
Field field = Dummy.class.getDeclaredField("i");
|
||||||
|
String name = field.getName();
|
||||||
|
String expected = name.toUpperCase(Locale.ROOT);
|
||||||
|
|
||||||
|
Locale oldLocale = Locale.getDefault();
|
||||||
|
// Set Turkish as Locale which has special case conversion rules
|
||||||
|
Locale.setDefault(new Locale("tr"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Verify that default Locale has different case conversion rules
|
||||||
|
assertNotEquals("Test setup is broken", expected, name.toUpperCase());
|
||||||
|
|
||||||
|
for (FieldNamingPolicy policy : policies) {
|
||||||
|
// Should ignore default Locale
|
||||||
|
assertEquals("Unexpected conversion for " + policy, expected, policy.translateName(field));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Locale.setDefault(oldLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lower casing policies should be unaffected by default Locale.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testLowerCasingLocaleIndependent() throws Exception {
|
||||||
|
class Dummy {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
int I;
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldNamingPolicy[] policies = {
|
||||||
|
FieldNamingPolicy.LOWER_CASE_WITH_DASHES,
|
||||||
|
FieldNamingPolicy.LOWER_CASE_WITH_DOTS,
|
||||||
|
FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES,
|
||||||
|
};
|
||||||
|
|
||||||
|
Field field = Dummy.class.getDeclaredField("I");
|
||||||
|
String name = field.getName();
|
||||||
|
String expected = name.toLowerCase(Locale.ROOT);
|
||||||
|
|
||||||
|
Locale oldLocale = Locale.getDefault();
|
||||||
|
// Set Turkish as Locale which has special case conversion rules
|
||||||
|
Locale.setDefault(new Locale("tr"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Verify that default Locale has different case conversion rules
|
||||||
|
assertNotEquals("Test setup is broken", expected, name.toLowerCase());
|
||||||
|
|
||||||
|
for (FieldNamingPolicy policy : policies) {
|
||||||
|
// Should ignore default Locale
|
||||||
|
assertEquals("Unexpected conversion for " + policy, expected, policy.translateName(field));
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Locale.setDefault(oldLocale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user