1 /*
2 * Copyright (C) 2008 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.gson;
18
19 import java.lang.reflect.Field;
20 import java.util.Locale;
21
22 /**
23 * An enumeration that defines a few standard naming conventions for JSON field names.
24 * This enumeration should be used in conjunction with {@link com.google.gson.GsonBuilder}
25 * to configure a {@link com.google.gson.Gson} instance to properly translate Java field
26 * names into the desired JSON field names.
27 *
28 * @author Inderjeet Singh
29 * @author Joel Leitch
30 */
31 public enum FieldNamingPolicy implements FieldNamingStrategy {
32
33 /**
34 * Using this naming policy with Gson will ensure that the field name is
35 * unchanged.
36 */
37 IDENTITY() {
38 @Override public String translateName(Field f) {
39 return f.getName();
40 }
41 },
42
43 /**
44 * Using this naming policy with Gson will ensure that the first "letter" of the Java
45 * field name is capitalized when serialized to its JSON form.
46 *
47 * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
48 * <ul>
49 * <li>someFieldName ---> SomeFieldName</li>
50 * <li>_someFieldName ---> _SomeFieldName</li>
51 * </ul>
52 */
53 UPPER_CAMEL_CASE() {
54 @Override public String translateName(Field f) {
55 return upperCaseFirstLetter(f.getName());
56 }
57 },
58
59 /**
60 * Using this naming policy with Gson will ensure that the first "letter" of the Java
61 * field name is capitalized when serialized to its JSON form and the words will be
62 * separated by a space.
63 *
64 * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
65 * <ul>
66 * <li>someFieldName ---> Some Field Name</li>
67 * <li>_someFieldName ---> _Some Field Name</li>
68 * </ul>
69 *
70 * @since 1.4
71 */
72 UPPER_CAMEL_CASE_WITH_SPACES() {
73 @Override public String translateName(Field f) {
74 return upperCaseFirstLetter(separateCamelCase(f.getName(), " "));
75 }
76 },
77
78 /**
79 * Using this naming policy with Gson will modify the Java Field name from its camel cased
80 * form to a lower case field name where each word is separated by an underscore (_).
81 *
82 * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
83 * <ul>
84 * <li>someFieldName ---> some_field_name</li>
85 * <li>_someFieldName ---> _some_field_name</li>
86 * <li>aStringField ---> a_string_field</li>
87 * <li>aURL ---> a_u_r_l</li>
88 * </ul>
89 */
90 LOWER_CASE_WITH_UNDERSCORES() {
91 @Override public String translateName(Field f) {
92 return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH);
93 }
94 },
95
96 /**
97 * Using this naming policy with Gson will modify the Java Field name from its camel cased
98 * form to a lower case field name where each word is separated by a dash (-).
99 *
100 * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
101 * <ul>
102 * <li>someFieldName ---> some-field-name</li>
103 * <li>_someFieldName ---> _some-field-name</li>
104 * <li>aStringField ---> a-string-field</li>
105 * <li>aURL ---> a-u-r-l</li>
106 * </ul>
107 * Using dashes in JavaScript is not recommended since dash is also used for a minus sign in
108 * expressions. This requires that a field named with dashes is always accessed as a quoted
109 * property like {@code myobject['my-field']}. Accessing it as an object field
110 * {@code myobject.my-field} will result in an unintended javascript expression.
111 * @since 1.4
112 */
113 LOWER_CASE_WITH_DASHES() {
114 @Override public String translateName(Field f) {
115 return separateCamelCase(f.getName(), "-").toLowerCase(Locale.ENGLISH);
116 }
117 },
118
119 /**
120 * Using this naming policy with Gson will modify the Java Field name from its camel cased
121 * form to a lower case field name where each word is separated by a dot (.).
122 *
123 * <p>Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":</p>
124 * <ul>
125 * <li>someFieldName ---> some.field.name</li>
126 * <li>_someFieldName ---> _some.field.name</li>
127 * <li>aStringField ---> a.string.field</li>
128 * <li>aURL ---> a.u.r.l</li>
129 * </ul>
130 * Using dots in JavaScript is not recommended since dot is also used for a member sign in
131 * expressions. This requires that a field named with dots is always accessed as a quoted
132 * property like {@code myobject['my.field']}. Accessing it as an object field
133 * {@code myobject.my.field} will result in an unintended javascript expression.
134 * @since 2.8
135 */
136 LOWER_CASE_WITH_DOTS() {
137 @Override public String translateName(Field f) {
138 return separateCamelCase(f.getName(), ".").toLowerCase(Locale.ENGLISH);
139 }
140 };
141
142 /**
143 * Converts the field name that uses camel-case define word separation into
144 * separate words that are separated by the provided {@code separatorString}.
145 */
146 static String separateCamelCase(String name, String separator) {
147 StringBuilder translation = new StringBuilder();
148 for (int i = 0, length = name.length(); i < length; i++) {
149 char character = name.charAt(i);
150 if (Character.isUpperCase(character) && translation.length() != 0) {
151 translation.append(separator);
152 }
153 translation.append(character);
154 }
155 return translation.toString();
156 }
157
158 /**
159 * Ensures the JSON field names begins with an upper case letter.
160 */
161 static String upperCaseFirstLetter(String name) {
162 int firstLetterIndex = 0;
163 int limit = name.length() - 1;
164 for(; !Character.isLetter(name.charAt(firstLetterIndex)) && firstLetterIndex < limit; ++firstLetterIndex);
165
166 char firstLetter = name.charAt(firstLetterIndex);
167 if(Character.isUpperCase(firstLetter)) { //The letter is already uppercased, return the original
168 return name;
169 }
170
171 char uppercased = Character.toUpperCase(firstLetter);
172 if(firstLetterIndex == 0) { //First character in the string is the first letter, saves 1 substring
173 return uppercased + name.substring(1);
174 }
175
176 return name.substring(0, firstLetterIndex) + uppercased + name.substring(firstLetterIndex + 1);
177 }
178 }
179