Skip to content

Commit 4e65e6a

Browse files
Give FieldNamingStrategy the ability to return multiple String names (#2776)
* Give FieldNamingStrategy the ability to return multiple String names * Fixed formatting violations * Code review changes - Changed fieldName to be added first to the fieldName list - test which verifies that when 'alternate names' are configured they don't affect serialization, and only affect deserialization - Updated translateToAlternateNames JavaDoc to refer it works like SerializedName#alternate() * Removed usage of Stream.concat Check Android compatibility test fails when using Stream.concat, switched to traditional Java method. * Code Review Changes 1. Renamed badname to primary-name 2. Added test deserializing TranslateName with translateToAlternateNames * Fixed typo * added @SInCE $next-version$ to translateToAlternateNames method * Renamed translateToAlternateNames to alternateNames * Merged the code with and without the SerializedName annotation * Improved FieldNamingStrategy JavaDoc for the alternateNames method. * Added special handling for annotation without alternate names * Moved Collections.singletonList block to apply to both cases * Update gson/src/main/java/com/google/gson/FieldNamingStrategy.java Co-authored-by: Marcono1234 <[email protected]> * Update gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java Co-authored-by: Marcono1234 <[email protected]> * Update gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java Co-authored-by: Marcono1234 <[email protected]> * Update gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java Co-authored-by: Marcono1234 <[email protected]> * Update gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java Co-authored-by: Marcono1234 <[email protected]> --------- Co-authored-by: Marcono1234 <[email protected]>
1 parent 6010131 commit 4e65e6a

File tree

3 files changed

+101
-9
lines changed

3 files changed

+101
-9
lines changed

gson/src/main/java/com/google/gson/FieldNamingStrategy.java

+15
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616

1717
package com.google.gson;
1818

19+
import com.google.gson.annotations.SerializedName;
1920
import java.lang.reflect.Field;
21+
import java.util.Collections;
22+
import java.util.List;
2023

2124
/**
2225
* A mechanism for providing custom field naming in Gson. This allows the client code to translate
@@ -37,4 +40,16 @@ public interface FieldNamingStrategy {
3740
* @since 1.3
3841
*/
3942
public String translateName(Field f);
43+
44+
/**
45+
* Returns alternative names for this field when it is being deserialized. This is similar to
46+
* {@link SerializedName#alternate()}.
47+
*
48+
* @param f the field object
49+
* @return the list of alternative field names.
50+
* @since $next-version$
51+
*/
52+
default List<String> alternateNames(Field f) {
53+
return Collections.emptyList();
54+
}
4055
}

gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapterFactory.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -84,21 +84,25 @@ private boolean includeField(Field f, boolean serialize) {
8484
/** first element holds the default name */
8585
@SuppressWarnings("MixedMutabilityReturnType")
8686
private List<String> getFieldNames(Field f) {
87+
88+
String fieldName;
89+
List<String> alternates;
8790
SerializedName annotation = f.getAnnotation(SerializedName.class);
8891
if (annotation == null) {
89-
String name = fieldNamingPolicy.translateName(f);
90-
return Collections.singletonList(name);
92+
fieldName = fieldNamingPolicy.translateName(f);
93+
alternates = fieldNamingPolicy.alternateNames(f);
94+
} else {
95+
fieldName = annotation.value();
96+
alternates = Arrays.asList(annotation.alternate());
9197
}
9298

93-
String serializedName = annotation.value();
94-
String[] alternates = annotation.alternate();
95-
if (alternates.length == 0) {
96-
return Collections.singletonList(serializedName);
99+
if (alternates.isEmpty()) {
100+
return Collections.singletonList(fieldName);
97101
}
98102

99-
List<String> fieldNames = new ArrayList<>(alternates.length + 1);
100-
fieldNames.add(serializedName);
101-
Collections.addAll(fieldNames, alternates);
103+
List<String> fieldNames = new ArrayList<>(alternates.size() + 1);
104+
fieldNames.add(fieldName);
105+
fieldNames.addAll(alternates);
102106
return fieldNames;
103107
}
104108

gson/src/test/java/com/google/gson/functional/NamingPolicyTest.java

+73
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.google.gson.common.TestTypes.ClassWithSerializedNameFields;
2727
import com.google.gson.common.TestTypes.StringWrapper;
2828
import java.lang.reflect.Field;
29+
import java.util.List;
2930
import java.util.Locale;
3031
import org.junit.Before;
3132
import org.junit.Test;
@@ -237,6 +238,78 @@ public void testAtSignInSerializedName() {
237238
assertThat(new Gson().toJson(new AtName())).isEqualTo("{\"@foo\":\"bar\"}");
238239
}
239240

241+
@Test
242+
public void testGsonWithNameDeserialiation() {
243+
Gson gson =
244+
builder
245+
.setFieldNamingStrategy(
246+
new FieldNamingStrategy() {
247+
248+
@Override
249+
public String translateName(Field f) {
250+
return "primary-name";
251+
}
252+
253+
@Override
254+
public List<String> alternateNames(Field f) {
255+
return List.of("alternate-name");
256+
}
257+
})
258+
.create();
259+
String target = "{\"primary-name\":\"someValue\"}";
260+
StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class);
261+
assertThat(deserializedObject.someConstantStringInstanceField).isEqualTo("someValue");
262+
}
263+
264+
@Test
265+
public void testGsonWithAlternateNamesDeserialiation() {
266+
Gson gson =
267+
builder
268+
.setFieldNamingStrategy(
269+
new FieldNamingStrategy() {
270+
271+
@Override
272+
public String translateName(Field f) {
273+
return "primary-name";
274+
}
275+
276+
@Override
277+
public List<String> alternateNames(Field f) {
278+
return List.of("alternate-name");
279+
}
280+
})
281+
.create();
282+
String target = "{\"alternate-name\":\"someValue\"}";
283+
StringWrapper deserializedObject = gson.fromJson(target, StringWrapper.class);
284+
assertThat(deserializedObject.someConstantStringInstanceField).isEqualTo("someValue");
285+
}
286+
287+
@Test
288+
public void testGsonWithAlternateNamesSerialization() {
289+
Gson gson =
290+
builder
291+
.setFieldNamingStrategy(
292+
new FieldNamingStrategy() {
293+
294+
@Override
295+
public String translateName(Field f) {
296+
return "some-constant-string-instance-field";
297+
}
298+
299+
@Override
300+
public List<String> alternateNames(Field f) {
301+
return List.of("alternate-name");
302+
}
303+
})
304+
.create();
305+
StringWrapper target = new StringWrapper("blah");
306+
assertThat(gson.toJson(target))
307+
.isEqualTo(
308+
"{\"some-constant-string-instance-field\":\""
309+
+ target.someConstantStringInstanceField
310+
+ "\"}");
311+
}
312+
240313
static final class AtName {
241314
@SerializedName("@foo")
242315
String f = "bar";

0 commit comments

Comments
 (0)