diff --git a/gson/src/main/java/com/google/gson/FieldNamingStrategy.java b/gson/src/main/java/com/google/gson/FieldNamingStrategy.java index 541588696e..eebd998dfa 100644 --- a/gson/src/main/java/com/google/gson/FieldNamingStrategy.java +++ b/gson/src/main/java/com/google/gson/FieldNamingStrategy.java @@ -16,7 +16,10 @@ package com.google.gson; +import com.google.gson.annotations.SerializedName; import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; /** * A mechanism for providing custom field naming in Gson. This allows the client code to translate @@ -37,4 +40,16 @@ public interface FieldNamingStrategy { * @since 1.3 */ public String translateName(Field f); + + /** + * Returns alternative names for this field when it is being deserialized. This is similar to + * {@link SerializedName#alternate()}. + * + * @param f the field object + * @return the list of alternative field names. + * @since $next-version$ + */ + default List alternateNames(Field f) { + return Collections.emptyList(); + } } diff --git a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java index 94396ff1eb..3447f0c331 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java +++ b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java @@ -84,21 +84,25 @@ private boolean includeField(Field f, boolean serialize) { /** first element holds the default name */ @SuppressWarnings("MixedMutabilityReturnType") private List getFieldNames(Field f) { + + String fieldName; + List alternates; SerializedName annotation = f.getAnnotation(SerializedName.class); if (annotation == null) { - String name = fieldNamingPolicy.translateName(f); - return Collections.singletonList(name); + fieldName = fieldNamingPolicy.translateName(f); + alternates = fieldNamingPolicy.alternateNames(f); + } else { + fieldName = annotation.value(); + alternates = Arrays.asList(annotation.alternate()); } - String serializedName = annotation.value(); - String[] alternates = annotation.alternate(); - if (alternates.length == 0) { - return Collections.singletonList(serializedName); + if (alternates.isEmpty()) { + return Collections.singletonList(fieldName); } - List fieldNames = new ArrayList<>(alternates.length + 1); - fieldNames.add(serializedName); - Collections.addAll(fieldNames, alternates); + List fieldNames = new ArrayList<>(alternates.size() + 1); + fieldNames.add(fieldName); + fieldNames.addAll(alternates); return fieldNames; } diff --git a/gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java b/gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java index c419f6155d..9369b2b744 100644 --- a/gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java +++ b/gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java @@ -26,6 +26,7 @@ import com.google.gson.common.TestTypes.ClassWithSerializedNameFields; import com.google.gson.common.TestTypes.StringWrapper; import java.lang.reflect.Field; +import java.util.List; import java.util.Locale; import org.junit.Before; import org.junit.Test; @@ -237,6 +238,78 @@ public void testAtSignInSerializedName() { assertThat(new Gson().toJson(new AtName())).isEqualTo("{\"@foo\":\"bar\"}"); } + @Test + public void testGsonWithNameDeserialiation() { + Gson gson = + builder + .setFieldNamingStrategy( + new FieldNamingStrategy() { + + @Override + public String translateName(Field f) { + return "primary-name"; + } + + @Override + public List alternateNames(Field f) { + return List.of("alternate-name"); + } + }) + .create(); + String target = "{\"primary-name\":\"someValue\"}"; + StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); + assertThat(deserializedObject.someConstantStringInstanceField).isEqualTo("someValue"); + } + + @Test + public void testGsonWithAlternateNamesDeserialiation() { + Gson gson = + builder + .setFieldNamingStrategy( + new FieldNamingStrategy() { + + @Override + public String translateName(Field f) { + return "primary-name"; + } + + @Override + public List alternateNames(Field f) { + return List.of("alternate-name"); + } + }) + .create(); + String target = "{\"alternate-name\":\"someValue\"}"; + StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class); + assertThat(deserializedObject.someConstantStringInstanceField).isEqualTo("someValue"); + } + + @Test + public void testGsonWithAlternateNamesSerialization() { + Gson gson = + builder + .setFieldNamingStrategy( + new FieldNamingStrategy() { + + @Override + public String translateName(Field f) { + return "some-constant-string-instance-field"; + } + + @Override + public List alternateNames(Field f) { + return List.of("alternate-name"); + } + }) + .create(); + StringWrapper target = new StringWrapper("blah"); + assertThat(gson.toJson(target)) + .isEqualTo( + "{\"some-constant-string-instance-field\":\"" + + target.someConstantStringInstanceField + + "\"}"); + } + static final class AtName { @SerializedName("@foo") String f = "bar";