Repository: incubator-beam Updated Branches: refs/heads/master 9bcf9b0a7 -> 8949ec315
[BEAM-359] Treat erased type variables as non-deterministic in AvroCoder Previously, loss of type information due to erasure would lead to an IllegalArgumentException in the constructor. Now, the coder is created and usable but treated as non-deterministic. Project: http://git-wip-us.apache.org/repos/asf/incubator-beam/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-beam/commit/9c8dc4fe Tree: http://git-wip-us.apache.org/repos/asf/incubator-beam/tree/9c8dc4fe Diff: http://git-wip-us.apache.org/repos/asf/incubator-beam/diff/9c8dc4fe Branch: refs/heads/master Commit: 9c8dc4fe920618253b425f0d998f8d63552ec358 Parents: 9bcf9b0 Author: bchambers <bchamb...@google.com> Authored: Tue Jun 21 13:42:33 2016 -0700 Committer: bchambers <bchamb...@google.com> Committed: Wed Jun 22 14:33:31 2016 -0700 ---------------------------------------------------------------------- .../org/apache/beam/sdk/coders/AvroCoder.java | 10 +++++--- .../apache/beam/sdk/coders/AvroCoderTest.java | 26 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-beam/blob/9c8dc4fe/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java ---------------------------------------------------------------------- diff --git a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java index 3b93ec3..00c1cbc 100644 --- a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java +++ b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/AvroCoder.java @@ -475,6 +475,10 @@ public class AvroCoder<T> extends StandardCoder<T> { checkMap(context, type, schema); break; case RECORD: + if (!(type.getType() instanceof Class)) { + reportError(context, "Cannot determine type from generic %s due to erasure", type); + return; + } checkRecord(type, schema); break; case UNION: @@ -695,7 +699,8 @@ public class AvroCoder<T> extends StandardCoder<T> { * Extract a field from a class. We need to look at the declared fields so that we can * see private fields. We may need to walk up to the parent to get classes from the parent. */ - private static Field getField(Class<?> clazz, String name) { + private static Field getField(Class<?> originalClazz, String name) { + Class<?> clazz = originalClazz; while (clazz != null) { for (Field field : clazz.getDeclaredFields()) { AvroName avroName = field.getAnnotation(AvroName.class); @@ -708,8 +713,7 @@ public class AvroCoder<T> extends StandardCoder<T> { clazz = clazz.getSuperclass(); } - throw new IllegalArgumentException( - "Unable to get field " + name + " from class " + clazz); + throw new IllegalArgumentException("Unable to get field " + name + " from " + originalClazz); } } } http://git-wip-us.apache.org/repos/asf/incubator-beam/blob/9c8dc4fe/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/AvroCoderTest.java ---------------------------------------------------------------------- diff --git a/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/AvroCoderTest.java b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/AvroCoderTest.java index 8f28cc4..207bfdd 100644 --- a/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/AvroCoderTest.java +++ b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/AvroCoderTest.java @@ -755,4 +755,30 @@ public class AvroCoderTest { return Objects.hash(getClass(), onlySomeTypesAllowed); } } + + @Test + public void testAvroCoderForGenerics() throws Exception { + Schema fooSchema = AvroCoder.of(Foo.class).getSchema(); + Schema schema = new Schema.Parser().parse("{" + + "\"type\":\"record\"," + + "\"name\":\"SomeGeneric\"," + + "\"namespace\":\"ns\"," + + "\"fields\":[" + + " {\"name\":\"foo\", \"type\":" + fooSchema.toString() + "}" + + "]}"); + @SuppressWarnings("rawtypes") + AvroCoder<SomeGeneric> coder = AvroCoder.of(SomeGeneric.class, schema); + + assertNonDeterministic(coder, + reasonField(SomeGeneric.class, "foo", "erasure")); + } + + private static class SomeGeneric<T> { + @SuppressWarnings("unused") + private T foo; + } + private static class Foo { + @SuppressWarnings("unused") + String id; + } }