Reputation: 8053
I have the misfortune to parse JSON data where different naming policies coexist.
{
"camelCaseData" : {
"someField" : 1
},
"snake_case_data" : {
"some_field" : 2
}
}
Is it possible to specify naming policy for the whole snakeCaseData
? Or another solution that helps to avoid manual annotating of each field by @SerializedName
?
Something like the following
class Data {
CamelCaseData camelCaseData;
@GsonNamingPolicy(com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES )
SnakeCaseData snakeCaseData;
}
Upvotes: 4
Views: 3778
Reputation: 13907
I can't get to exactly what you were asking for, but I think this might help you anyway. Basically this would require you to annotate any class that contains only snake-case fields, and any snake-case fields in classes that also contain camel-case fields.
First we define an annotation like you suggested:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.TYPE})
public @interface GsonNamingPolicy {
FieldNamingPolicy value();
}
Then we would annotate the classes as I described above:
public static class CamelCaseData {
int someField;
}
@GsonNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
public static class SnakeCaseData {
int someField;
}
public static class Data {
CamelCaseData camelCaseData;
@GsonNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
SnakeCaseData snakeCaseData;
}
Finally we define a custom FieldNamingStrategy
, which checks the field and its declaring class for our new annotation. If the annotation is present, the policy defined in the annotation is used, otherwise it just uses a default policy.
public static class AnnotationFieldNamingStrategy implements FieldNamingStrategy {
public String translateName(Field field) {
Class<?> declaringClass = field.getDeclaringClass();
GsonNamingPolicy fieldNamingPolicy = field.getAnnotation(GsonNamingPolicy.class);
GsonNamingPolicy classNamingPolicy = declaringClass.getAnnotation(GsonNamingPolicy.class);
FieldNamingPolicy policy = FieldNamingPolicy.IDENTITY;
if (fieldNamingPolicy != null) {
policy = fieldNamingPolicy.value();
} else if (classNamingPolicy != null) {
policy = classNamingPolicy.value();
}
return policy.translateName(field);
}
}
You can then use this strategy when configuring Gson:
Gson gson = new GsonBuilder()
.setFieldNamingStrategy(new AnnotationFieldNamingStrategy())
.create();
Data data = gson.fromJson(json, Data.class);
System.out.println(data.camelCaseData.someField);
System.out.println(data.snakeCaseData.someField);
This is not exactly what you were asking for, but hopefully it helps you anyway. I don't believe there is a way to check whether a field is annotated at a level beyond the class that declared it. It's possible there is a way to achieve what you are looking for, but it may require working with a custom TypeAdapter
or TypeAdapterFactory
.
Upvotes: 4