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