简体   繁体   中英

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

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();

There is an easier way to almost get what you want. I'd not realised but since GSON 2.4 the SerializedName annotation supports an array of alternate names that GSON can deserialise from.

public class Foo {
    @SerializedName(value = "firstName", alternate = {"firstname", "Firstname"})
    private String firstName;

    public java.lang.String getFirstName() {
        return firstName;
    }

    @Override
    public String toString() {
        return "Foo:" + firstName;
    }
}

You could use this to support the likely variations without being able to handle something like "firSTNAme".

https://google.github.io/gson/apidocs/com/google/gson/annotations/SerializedName.html

It doesn't look as though GSON has an easy built in way to customise it the way you want. It looks as though technically you could implement a TypeAdapterFactory that uses reflection to do this but it seems excessive.

You might open a feature request with GSON about introducing support for field naming strategies that support alternative names or pattern, or case insensitive matching.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM