Reputation: 4902
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();
Upvotes: 20
Views: 21293
Reputation: 874
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.
Upvotes: 13
Reputation: 3295
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.
Upvotes: 30
Reputation: 3295
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.
Upvotes: 5