How does GSON handle spaces in variable names?

3,609 views
Skip to first unread message

JP

unread,
May 25, 2010, 8:04:15 PM5/25/10
to google-gson
Let's say I have a JSON file that looks like this:
{
"First Name":"John",
"Last Name":"Smith"
}

How would GSON handle that? How would it be possible for me to make a
class to read this file into? Obviously I can't have spaces in my
variable names.

Joel

unread,
May 25, 2010, 9:01:00 PM5/25/10
to google-gson
You should be able to use the field naming support to handle this use
case. Let's assume you want to serialize the above JSON into the
following class:

public class Name {
private final String firstName;
private final String lastName;

// Used for deserialization
private Name() {
this("", "");
}

public Name(String firstName, String lastName) {
this.firstName = Preconditions.checkNotNull(firstName);
this.lastName = Preconditions.checkNotNull(lastName);
}

public String getFirstName() {
return firstName;
}

public String getLastName() {
return lastName;
}

public String getFullName() {
return getFirstName() + " " + getLastName();
}
}

-----------------------------------------

For this case, I can see two different options:

Option #1 - You can modify the "Name" class. Now your implementation
would look as follows:
public class Name {
@SerializedName("First Name") private final String firstName;
@SerializedName("Last Name") private final String lastName;

// Everything else stays the same
}

Option #2 - Create your own FieldNamingStrategy implementation. This
approach is preferred if in general you want to convert all Java
fields from the common pattern "someFieldName" to "Some Field Name".
This general naming strategy would be implemented as follows (NOTE:
this is for Gson 1.4):

public MyNamingStrategy implements FieldNamingStrategy2 {
@Override
public String translateName(FieldAttributes f) {
String fieldName = capitalizedFirstLetter(f.getName());
return insertWordSplitterToken(fieldName, " ");
}

private static String capitalizeFirstLetter(String target) {
char firstCharacter = target.charAt(index);
if (!Character.isUpperCase(firstCharacter)) {
return Character.toUpperCase(firstCharacter) +
target.substring(1);
} else {
return target;
}
}

private static String insertWordSplitterToken(String target, String
separatorToken) {
StringBuilder translation = new StringBuilder();
for (int i = 0; i < target.length(); i++) {
char character = target.charAt(i);
if (Character.isUpperCase(character) && translation.length() !=
0) {
translation.append(separatorToken);
}
translation.append(character);
}

return translation.toString();
}
}

Now you would create your Gson instance as follows:
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new MyNamingStrategy())
.create();


Not sure how common this is, but if multiple clients use this
"spacing" naming policy then maybe it would be wise to implement is as
a supported "FieldNamingPolicy".

Hope this helps,
Joel

JP

unread,
May 26, 2010, 9:43:01 AM5/26/10
to google-gson
Thanks for the response! Those seem like good ideas. I tried the
first one first b/c it looked easier but this wouldn't compile:
class Person
{
@Serialized("First Name")
String firstName;
@Serialized("Last Name")
String lastName;
}

I changed it to:
class Person
{
@SerializedName("First Name")


String firstName;
@SerializedName("Last Name")

String lastName;
}

but got this error:
Exception in thread "main" java.lang.IllegalArgumentException: First
Name is not a valid JSON field name.
at
com.google.gson.JsonFieldNameValidator.validate(JsonFieldNameValidator.java:
63)
at
com.google.gson.SerializedNameAnnotationInterceptingNamingPolicy.translateName(SerializedNameAnnotationInterceptingNamingPolicy.java:
48)
at
com.google.gson.JsonObjectDeserializationVisitor.getFieldName(JsonObjectDeserializationVisitor.java:
93)
at
com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler(JsonObjectDeserializationVisitor.java:
98)
at
com.google.gson.ObjectNavigator.navigateClassFields(ObjectNavigator.java:
141)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:122)
at
com.google.gson.JsonDeserializationContextDefault.fromJsonObject(JsonDeserializationContextDefault.java:
73)
at
com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:
49)
at com.google.gson.Gson.fromJson(Gson.java:379)
at com.google.gson.Gson.fromJson(Gson.java:352)
at Tester.main(Tester.java:15)

and this is my json file:


{
"First Name": "John",
"Last Name": "Smith"
}

JP

unread,
May 26, 2010, 9:44:48 AM5/26/10
to google-gson
I misread, it's supposed to be @SerializedName, not @Serialized. My
bad. What's that error message mean though?

JP

unread,
May 26, 2010, 10:00:04 AM5/26/10
to google-gson
I think you're giving me code to do the opposite of what I want to
do. I tried this code:
public class Tester
{
public static void main(String[] args) throws JsonParseException,
FileNotFoundException
{
GsonBuilder gson = new GsonBuilder();
gson.setFieldNamingStrategy(new MyNamingStrategy());
Gson g = gson.create();
Person p= g.fromJson(new BufferedReader(new
FileReader("simple.txt")), Person.class);
System.out.println(p.firstName+" "+p.lastName);
}
}
class Person
{
String firstName;
String lastName;
}

class MyNamingStrategy implements FieldNamingStrategy
{
@Override
public String translateName(Field f)
{
System.out.println("Field: "+f.getName());
String name = f.getName().replace(" ","");
String toReturn = (name.charAt(0)+"").toLowerCase() +
name.substring(1);
System.out.println(toReturn);
return toReturn;
}
}

When it prints the f.getName() it prints the name of the variable in
the Person class, rather than the name of the field in the JSON file.
My problem is that the names of my fields in the JSON file have spaces
in them and I want to put them into a class without spaces in variable
names.

Joel

unread,
May 26, 2010, 1:43:13 PM5/26/10
to google-gson
OK, I see the issue. Our JSON field name validator disallows "spaces"
in the name.

This is fixed in r546 which will be included in the full 1.4 Gson
release.

As an FYI, the Field Naming Strategies map for Java to the JSON
representation. This is because we take the Java Class object as the
source of truth and map it to its JSON representation.

Hope this helps,
Joel

JP

unread,
May 26, 2010, 1:43:50 PM5/26/10
to google-gson
I wrote a file parser to just change all field names with spaces into
field names without spaces. Not ideal but, I guess thats my only
option

Joel

unread,
May 26, 2010, 7:51:30 PM5/26/10
to google-gson
If you'd like then I can send you a new jar that has this
functionality? Or you can build your own deployment jar of this
project from HEAD. With the new jar then both options that I
explained above would work; however, Option 2 would be simplified to:

Gson gson = new GsonBuilder()

.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)
.create();

Let me know,
Joel

JP

unread,
May 27, 2010, 1:43:40 PM5/27/10
to google-gson
Yea if you could email me that jar, that would be great.
FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES, does that just change
"First Name" to firstName. Thanks

Florian

unread,
Aug 7, 2011, 11:37:09 AM8/7/11
to googl...@googlegroups.com
I had almost the same problem (it is not possible to name a variable 'abstract' in Java). I solved it this way:

public class MyFieldNamingStrategy implements FieldNamingStrategy {

    public String translateName(Field arg0) {
        String result = "";
        String name = arg0.getName().substring(1);
        for(char ch : name.toCharArray()){
            result += ((Character.isUpperCase(ch)) ? "_" : "") + Character.toLowerCase(ch);
        }
        return result;
    }

}

While deserializing a json file, gson is going to have a look for the representative variable in our class. With this FieldNameStrategy my java variable _abstract is now going to be mapped to the json fieldname "abstract". (first character is going to be removed). Also i am converting my camelcase into a underscore seperated name. _geoFacet (Java) -> geo_facet (json).

Hope this will help anybody :)
Reply all
Reply to author
Forward
0 new messages