Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON - Deserialize case insensitive field name (no definite case pattern)

Tags:

java

gson

I want to build a flexible api, I have no definite case sensitivity the user can pass, so GSON must be able to deserialize this in case sensitive.

{"firstName":"Juan"}
{"firstname":"Juan"}
{"Firstname":"Juan"}
...

How can I deserialize these field into my Foo's firstName?

public class Foo {
    private String firstName;
    //..getters
}

I tried to use FieldNamingPolicy, but it did not work.

new GsonBuilder()
            .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
            .setPrettyPrinting()
            .create();
like image 708
richersoon Avatar asked Mar 18 '16 10:03

richersoon


2 Answers

I think you will need to implement a custom JsonDeserialiser. The field naming policy and strategy appears to provide a way to map Java field names to JSON properties but not JSON properties to Java field names.

This deserialiser will ignore the case of the name of the property and try to match it against "firstname".

public final class FooDeserialiser implements JsonDeserializer<Foo> {

    @Override
    public Foo deserialize(
        JsonElement jsonElement,
        Type type,
        JsonDeserializationContext jsonDeserializationContext)
        throws JsonParseException {

        for (Map.Entry<String, JsonElement> property : jsonElement.getAsJsonObject().entrySet()) {
            if ("firstname".equalsIgnoreCase(property.getKey())) {
                return new Foo(property.getValue().getAsString());
            }
        }
        // Or return null if you prefer, or return a Foo with null as the first name
        // It has failed to find any property that looks like firstname
        throw new JsonParseException("No firstName property");
    }
}

This can be registered as a type adapter with the Gson object when it is being built like this:

final Gson gson = new GsonBuilder()
        .registerTypeAdapter(Foo.class, new FooDeserialiser())
        .setPrettyPrinting()
        .create();

And then invoked like:

final List<Foo> foos = gson.fromJson(
        "[{\"firstName\":\"Juan\"},{\"firstname\":\"Juan\"},{\"Firstname\":\"Juan\"}]",
        new TypeToken<List<Foo>>() {}.getType());

To return a list for Foo objects each with the first name Juan.

The only problem is building the deserialisers for your objects may become a burden. Your deserialisers will need to be more complicated than the above example.

like image 149
Matt Champion Avatar answered Oct 17 '22 14:10

Matt Champion


Not a complete solution to this problem but if the keys happen to be all lowercase such as headimgurl then you can implement FieldNamingStrategy interface

Gson gson = new GsonBuilder().setFieldNamingStrategy(f -> f.getName().toLowerCase()).create();

to parse the value to headImgUrl field of the object.

like image 9
Ivan Huang Avatar answered Oct 17 '22 15:10

Ivan Huang