Skip to content

Commit b4e391e

Browse files
ehlyzovdhalperi
authored andcommitted
[BEAM-359] Treat erased type variables as non-deterministic in AvroCoder (GoogleCloudPlatform#531)
1 parent efd33cc commit b4e391e

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

sdk/src/main/java/com/google/cloud/dataflow/sdk/coders/AvroCoder.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,10 @@ private void doCheck(String context, TypeDescriptor<?> type, Schema schema) {
474474
checkMap(context, type, schema);
475475
break;
476476
case RECORD:
477+
if (!(type.getType() instanceof Class)) {
478+
reportError(context, "Cannot determine type from generic %s due to erasure", type);
479+
return;
480+
}
477481
checkRecord(type, schema);
478482
break;
479483
case UNION:
@@ -694,7 +698,8 @@ private void checkArray(String context, TypeDescriptor<?> type, Schema schema) {
694698
* Extract a field from a class. We need to look at the declared fields so that we can
695699
* see private fields. We may need to walk up to the parent to get classes from the parent.
696700
*/
697-
private static Field getField(Class<?> clazz, String name) {
701+
private static Field getField(Class<?> originalClazz, String name) {
702+
Class<?> clazz = originalClazz;
698703
while (clazz != null) {
699704
for (Field field : clazz.getDeclaredFields()) {
700705
AvroName avroName = field.getAnnotation(AvroName.class);
@@ -708,7 +713,7 @@ private static Field getField(Class<?> clazz, String name) {
708713
}
709714

710715
throw new IllegalArgumentException(
711-
"Unable to get field " + name + " from class " + clazz);
716+
"Unable to get field " + name + " from class " + originalClazz);
712717
}
713718
}
714719
}

sdk/src/test/java/com/google/cloud/dataflow/sdk/coders/AvroCoderTest.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,4 +751,30 @@ public int hashCode() {
751751
return Objects.hash(getClass(), onlySomeTypesAllowed);
752752
}
753753
}
754+
755+
@Test
756+
public void testAvroCoderForGenerics() throws Exception {
757+
Schema fooSchema = AvroCoder.of(Foo.class).getSchema();
758+
Schema schema = new Schema.Parser().parse("{"
759+
+ "\"type\":\"record\","
760+
+ "\"name\":\"SomeGeneric\","
761+
+ "\"namespace\":\"ns\","
762+
+ "\"fields\":["
763+
+ " {\"name\":\"foo\", \"type\":" + fooSchema.toString() + "}"
764+
+ "]}");
765+
@SuppressWarnings("rawtypes")
766+
AvroCoder<SomeGeneric> coder = AvroCoder.of(SomeGeneric.class, schema);
767+
768+
assertNonDeterministic(coder,
769+
reasonField(SomeGeneric.class, "foo", "erasure"));
770+
}
771+
772+
private static class SomeGeneric<T> {
773+
@SuppressWarnings("unused")
774+
private T foo;
775+
}
776+
private static class Foo {
777+
@SuppressWarnings("unused")
778+
String id;
779+
}
754780
}

0 commit comments

Comments
 (0)