diff --git a/CHANGES.txt b/CHANGES.txt index fb9d7c0149c..3266b373343 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -18,6 +18,8 @@ Avro 1.3.3 (Unreleased) AVRO-548. Python client should handle CLIENT handshake match status correctly. (hammer) + AVRO-517. Resolving Decoder fails in some cases. (thiru) + Avro 1.3.2 (31 March 2010) IMPROVEMENTS diff --git a/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java b/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java index 23759184850..91ff3010273 100644 --- a/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java +++ b/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java @@ -67,7 +67,10 @@ public D read(D reuse, Decoder in) throws IOException { if (resolver == null) { resolver = ResolvingDecoder.resolve(actual, expected); } - return (D) read(reuse, expected, new ResolvingDecoder(resolver, in)); + ResolvingDecoder r = new ResolvingDecoder(resolver, in); + D result = (D) read(reuse, expected, r); + r.drain(); + return result; } /** Called to read data.*/ diff --git a/lang/java/src/java/org/apache/avro/io/ResolvingDecoder.java b/lang/java/src/java/org/apache/avro/io/ResolvingDecoder.java index f64ca154336..cfd76c1091f 100644 --- a/lang/java/src/java/org/apache/avro/io/ResolvingDecoder.java +++ b/lang/java/src/java/org/apache/avro/io/ResolvingDecoder.java @@ -121,6 +121,25 @@ public final Schema.Field[] readFieldOrder() throws IOException { return ((Symbol.FieldOrderAction) parser.advance(Symbol.FIELD_ACTION)). fields; } + + /** + * Consume any more data that has been written by the writer but not + * needed by the reader so that the the underlying decoder is in proper + * shape for the next record. This situation happens when, for example, + * the writer writes a record with two fields and the reader needs only the + * first field. + * + * This function should be called after completely decoding an object but + * before next object can be decoded from the same underlying decoder + * either directly or through another resolving decoder. If the same resolving + * decoder is used for the next object as well, calling this method is + * optional; the state of this resolving decoder ensures that any leftover + * portions are consumed before the next object is decoded. + * @throws IOException + */ + public final void drain() throws IOException { + parser.processImplicitActions(); + } @Override public long readLong() throws IOException { diff --git a/lang/java/src/test/java/org/apache/avro/io/TestResolvingIOResolving.java b/lang/java/src/test/java/org/apache/avro/io/TestResolvingIOResolving.java index e0100795854..35382c59a4d 100644 --- a/lang/java/src/test/java/org/apache/avro/io/TestResolvingIOResolving.java +++ b/lang/java/src/test/java/org/apache/avro/io/TestResolvingIOResolving.java @@ -79,6 +79,16 @@ public static Collection data3() { private static Object[][] dataForResolvingTests() { // The mnemonics are the same as {@link TestValidatingIO#testSchemas} return new Object[][] { + // Projection + { "{\"type\":\"record\",\"name\":\"r\",\"fields\":[" + + "{\"name\":\"f1\", \"type\":\"string\"}," + + "{\"name\":\"f2\", \"type\":\"string\"}," + + "{\"name\":\"f3\", \"type\":\"int\"}]}", "S10S10IS10S10I", + new Object[] { "s1", "s2", 100, "t1", "t2", 200 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":[" + + "{\"name\":\"f1\", \"type\":\"string\" }," + + "{\"name\":\"f2\", \"type\":\"string\"}]}", "RS10S10RS10S10", + new Object[] { "s1", "s2", "t1", "t2" } }, // Reordered fields { "{\"type\":\"record\",\"name\":\"r\",\"fields\":[" + "{\"name\":\"f1\", \"type\":\"int\"},"