Java protobuf uses lower camel for all field names. When using reflection to find the generic type of repeated fields, can't use the user specified formats for field name conversion. (#1119)

This commit is contained in:
Ori Schwartz 2017-09-18 02:46:52 -04:00 committed by inder123
parent 558c13918e
commit f0aa1118e9
3 changed files with 50 additions and 9 deletions

View File

@ -19,7 +19,6 @@ package com.google.gson.protobuf;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import com.google.common.collect.MapMaker; import com.google.common.collect.MapMaker;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext;
@ -94,7 +93,8 @@ public class ProtoTypeAdapter
private final Set<Extension<FieldOptions, String>> serializedNameExtensions; private final Set<Extension<FieldOptions, String>> serializedNameExtensions;
private final Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions; private final Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions;
private EnumSerialization enumSerialization; private EnumSerialization enumSerialization;
private Converter<String, String> fieldNameSerializationFormat; private CaseFormat protoFormat;
private CaseFormat jsonFormat;
private Builder(EnumSerialization enumSerialization, CaseFormat fromFieldNameFormat, private Builder(EnumSerialization enumSerialization, CaseFormat fromFieldNameFormat,
CaseFormat toFieldNameFormat) { CaseFormat toFieldNameFormat) {
@ -126,7 +126,8 @@ public class ProtoTypeAdapter
*/ */
public Builder setFieldNameSerializationFormat(CaseFormat fromFieldNameFormat, public Builder setFieldNameSerializationFormat(CaseFormat fromFieldNameFormat,
CaseFormat toFieldNameFormat) { CaseFormat toFieldNameFormat) {
fieldNameSerializationFormat = fromFieldNameFormat.converterTo(toFieldNameFormat); this.protoFormat = fromFieldNameFormat;
this.jsonFormat = toFieldNameFormat;
return this; return this;
} }
@ -174,7 +175,7 @@ public class ProtoTypeAdapter
} }
public ProtoTypeAdapter build() { public ProtoTypeAdapter build() {
return new ProtoTypeAdapter(enumSerialization, fieldNameSerializationFormat, return new ProtoTypeAdapter(enumSerialization, protoFormat, jsonFormat,
serializedNameExtensions, serializedEnumValueExtensions); serializedNameExtensions, serializedEnumValueExtensions);
} }
} }
@ -195,16 +196,19 @@ public class ProtoTypeAdapter
new MapMaker().makeMap(); new MapMaker().makeMap();
private final EnumSerialization enumSerialization; private final EnumSerialization enumSerialization;
private final Converter<String, String> fieldNameSerializationFormat; private final CaseFormat protoFormat;
private final CaseFormat jsonFormat;
private final Set<Extension<FieldOptions, String>> serializedNameExtensions; private final Set<Extension<FieldOptions, String>> serializedNameExtensions;
private final Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions; private final Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions;
private ProtoTypeAdapter(EnumSerialization enumSerialization, private ProtoTypeAdapter(EnumSerialization enumSerialization,
Converter<String, String> fieldNameSerializationFormat, CaseFormat protoFormat,
CaseFormat jsonFormat,
Set<Extension<FieldOptions, String>> serializedNameExtensions, Set<Extension<FieldOptions, String>> serializedNameExtensions,
Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions) { Set<Extension<EnumValueOptions, String>> serializedEnumValueExtensions) {
this.enumSerialization = enumSerialization; this.enumSerialization = enumSerialization;
this.fieldNameSerializationFormat = fieldNameSerializationFormat; this.protoFormat = protoFormat;
this.jsonFormat = jsonFormat;
this.serializedNameExtensions = serializedNameExtensions; this.serializedNameExtensions = serializedNameExtensions;
this.serializedEnumValueExtensions = serializedEnumValueExtensions; this.serializedEnumValueExtensions = serializedEnumValueExtensions;
} }
@ -284,8 +288,9 @@ public class ProtoTypeAdapter
protoBuilder.setField(fieldDescriptor, fieldValue); protoBuilder.setField(fieldDescriptor, fieldValue);
} else if (fieldDescriptor.isRepeated()) { } else if (fieldDescriptor.isRepeated()) {
// If the type is an array, then we have to grab the type from the class. // If the type is an array, then we have to grab the type from the class.
// protobuf java field names are always lower camel case
String protoArrayFieldName = String protoArrayFieldName =
fieldNameSerializationFormat.convert(fieldDescriptor.getName()) + "_"; protoFormat.to(CaseFormat.LOWER_CAMEL, fieldDescriptor.getName()) + "_";
Field protoArrayField = protoClass.getDeclaredField(protoArrayFieldName); Field protoArrayField = protoClass.getDeclaredField(protoArrayFieldName);
Type protoArrayFieldType = protoArrayField.getGenericType(); Type protoArrayFieldType = protoArrayField.getGenericType();
fieldValue = context.deserialize(jsonElement, protoArrayFieldType); fieldValue = context.deserialize(jsonElement, protoArrayFieldType);
@ -325,7 +330,7 @@ public class ProtoTypeAdapter
return options.getExtension(extension); return options.getExtension(extension);
} }
} }
return fieldNameSerializationFormat.convert(defaultName); return protoFormat.to(jsonFormat, defaultName);
} }
/** /**

View File

@ -24,6 +24,11 @@ message SimpleProto {
optional int32 count = 2; optional int32 count = 2;
} }
message ProtoWithDifferentCaseFormat {
repeated string name_that_tests_case_format = 1;
optional string another_field = 2;
}
message ProtoWithRepeatedFields { message ProtoWithRepeatedFields {
repeated int64 numbers = 1; repeated int64 numbers = 1;
repeated SimpleProto simples = 2; repeated SimpleProto simples = 2;

View File

@ -15,10 +15,13 @@
*/ */
package com.google.gson.protobuf.functional; package com.google.gson.protobuf.functional;
import com.google.common.base.CaseFormat;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.protobuf.ProtoTypeAdapter; import com.google.gson.protobuf.ProtoTypeAdapter;
import com.google.gson.protobuf.ProtoTypeAdapter.EnumSerialization; import com.google.gson.protobuf.ProtoTypeAdapter.EnumSerialization;
import com.google.gson.protobuf.generated.Bag.ProtoWithDifferentCaseFormat;
import com.google.gson.protobuf.generated.Bag.ProtoWithRepeatedFields; import com.google.gson.protobuf.generated.Bag.ProtoWithRepeatedFields;
import com.google.gson.protobuf.generated.Bag.SimpleProto; import com.google.gson.protobuf.generated.Bag.SimpleProto;
import com.google.protobuf.GeneratedMessage; import com.google.protobuf.GeneratedMessage;
@ -32,6 +35,7 @@ import junit.framework.TestCase;
*/ */
public class ProtosWithComplexAndRepeatedFieldsTest extends TestCase { public class ProtosWithComplexAndRepeatedFieldsTest extends TestCase {
private Gson gson; private Gson gson;
private Gson upperCamelGson;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
@ -43,6 +47,14 @@ public class ProtosWithComplexAndRepeatedFieldsTest extends TestCase {
.setEnumSerialization(EnumSerialization.NUMBER) .setEnumSerialization(EnumSerialization.NUMBER)
.build()) .build())
.create(); .create();
upperCamelGson =
new GsonBuilder()
.registerTypeHierarchyAdapter(
GeneratedMessage.class, ProtoTypeAdapter.newBuilder()
.setFieldNameSerializationFormat(
CaseFormat.LOWER_UNDERSCORE, CaseFormat.UPPER_CAMEL)
.build())
.create();
} }
public void testSerializeRepeatedFields() { public void testSerializeRepeatedFields() {
@ -67,4 +79,23 @@ public class ProtosWithComplexAndRepeatedFieldsTest extends TestCase {
assertEquals("bar", proto.getSimples(0).getMsg()); assertEquals("bar", proto.getSimples(0).getMsg());
assertEquals(7, proto.getSimples(1).getCount()); assertEquals(7, proto.getSimples(1).getCount());
} }
public void testSerializeDifferentCaseFormat() {
final ProtoWithDifferentCaseFormat proto =
ProtoWithDifferentCaseFormat.newBuilder()
.setAnotherField("foo")
.addNameThatTestsCaseFormat("bar")
.build();
final JsonObject json = upperCamelGson.toJsonTree(proto).getAsJsonObject();
assertEquals("foo", json.get("AnotherField").getAsString());
assertEquals("bar", json.get("NameThatTestsCaseFormat").getAsJsonArray().get(0).getAsString());
}
public void testDeserializeDifferentCaseFormat() {
final String json = "{NameThatTestsCaseFormat:['bar'],AnotherField:'foo'}";
ProtoWithDifferentCaseFormat proto =
upperCamelGson.fromJson(json, ProtoWithDifferentCaseFormat.class);
assertEquals("foo", proto.getAnotherField());
assertEquals("bar", proto.getNameThatTestsCaseFormat(0));
}
} }