You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by cu...@apache.org on 2012/05/17 23:12:44 UTC

svn commit: r1339864 - in /avro/trunk: ./ lang/java/avro/src/main/java/org/apache/avro/reflect/ lang/java/avro/src/test/java/org/apache/avro/ lang/java/avro/src/test/java/org/apache/avro/reflect/ lang/java/avro/src/test/java/org/apache/avro/specific/ l...

Author: cutting
Date: Thu May 17 21:12:43 2012
New Revision: 1339864

URL: http://svn.apache.org/viewvc?rev=1339864&view=rev
Log:
AVRO-1046. Java: Fix ReflectDatumReader to be able to read generic and specific arrays.

Added:
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java   (with props)
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java   (with props)
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java   (with props)
    avro/trunk/lang/java/avro/src/test/resources/
    avro/trunk/lang/java/avro/src/test/resources/FooBarSpecificRecord.avsc
Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1339864&r1=1339863&r2=1339864&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Thu May 17 21:12:43 2012
@@ -65,6 +65,9 @@ Avro 1.7.0 (unreleased)
     backing array.  Also fix reflection to correctly read ByteBuffer
     fields.  (cutting)
 
+    AVRO-1046. Java: Fix ReflectDatumReader to be able to read generic
+    or specific arrays. (cutting)
+
 Avro 1.6.3 (5 March 2012)
 
     AVRO-1077. Missing 'inline' for union set function. (thiru)

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java?rev=1339864&r1=1339863&r2=1339864&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java Thu May 17 21:12:43 2012
@@ -268,6 +268,7 @@ public class ReflectData extends Specifi
           return result;
         }
         Schema result = Schema.createArray(createSchema(component, names));
+        result.addProp(CLASS_PROP, c.getName());
         setElement(result, component);
         return result;
       }

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java?rev=1339864&r1=1339863&r2=1339864&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java Thu May 17 21:12:43 2012
@@ -59,9 +59,16 @@ public class ReflectDatumReader<T> exten
   @Override
   @SuppressWarnings(value="unchecked")
   protected Object newArray(Object old, int size, Schema schema) {
-    ReflectData data = ReflectData.get();
-    Class collectionClass = ReflectData.getClassProp(schema, ReflectData.CLASS_PROP);
-    if (collectionClass != null) {
+    Class collectionClass =
+      ReflectData.getClassProp(schema, ReflectData.CLASS_PROP);
+    Class elementClass =
+      ReflectData.getClassProp(schema, ReflectData.ELEMENT_PROP);
+
+    if (collectionClass == null && elementClass == null)
+      return super.newArray(old, size, schema);   // use specific/generic
+
+    ReflectData data = (ReflectData)getData();
+    if (collectionClass != null && !collectionClass.isArray()) {
       if (old instanceof Collection) {
         ((Collection)old).clear();
         return old;
@@ -70,7 +77,7 @@ public class ReflectDatumReader<T> exten
         return new ArrayList();
       return data.newInstance(collectionClass, schema);
     }
-    Class elementClass = ReflectData.getClassProp(schema, ReflectData.ELEMENT_PROP);
+
     if (elementClass == null)
       elementClass = data.getClass(schema.getElementType());
     return Array.newInstance(elementClass, size);

Added: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java?rev=1339864&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java (added)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java Thu May 17 21:12:43 2012
@@ -0,0 +1,169 @@
+/**
+ * Autogenerated by Avro
+ * 
+ * DO NOT EDIT DIRECTLY
+ */
+package org.apache.avro;  
+@SuppressWarnings("all")
+public class FooBarSpecificRecord extends org.apache.avro.specific.SpecificRecordBase implements org.apache.avro.specific.SpecificRecord {
+  public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("{\"type\":\"record\",\"name\":\"FooBarSpecificRecord\",\"namespace\":\"org.apache.avro\",\"fields\":[{\"name\":\"id\",\"type\":\"int\"},{\"name\":\"relatedids\",\"type\":{\"type\":\"array\",\"items\":\"int\"}}]}");
+  @Deprecated public int id;
+  @Deprecated public java.util.List<java.lang.Integer> relatedids;
+  public org.apache.avro.Schema getSchema() { return SCHEMA$; }
+  // Used by DatumWriter.  Applications should not call. 
+  public java.lang.Object get(int field$) {
+    switch (field$) {
+    case 0: return id;
+    case 1: return relatedids;
+    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
+    }
+  }
+  // Used by DatumReader.  Applications should not call. 
+  @SuppressWarnings(value="unchecked")
+  public void put(int field$, java.lang.Object value$) {
+    switch (field$) {
+    case 0: id = (java.lang.Integer)value$; break;
+    case 1: relatedids = (java.util.List<java.lang.Integer>)value$; break;
+    default: throw new org.apache.avro.AvroRuntimeException("Bad index");
+    }
+  }
+
+  /**
+   * Gets the value of the 'id' field.
+   */
+  public java.lang.Integer getId() {
+    return id;
+  }
+
+  /**
+   * Sets the value of the 'id' field.
+   * @param value the value to set.
+   */
+  public void setId(java.lang.Integer value) {
+    this.id = value;
+  }
+
+  /**
+   * Gets the value of the 'relatedids' field.
+   */
+  public java.util.List<java.lang.Integer> getRelatedids() {
+    return relatedids;
+  }
+
+  /**
+   * Sets the value of the 'relatedids' field.
+   * @param value the value to set.
+   */
+  public void setRelatedids(java.util.List<java.lang.Integer> value) {
+    this.relatedids = value;
+  }
+
+  /** Creates a new FooBarSpecificRecord RecordBuilder */
+  public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder() {
+    return new org.apache.avro.FooBarSpecificRecord.Builder();
+  }
+  
+  /** Creates a new FooBarSpecificRecord RecordBuilder by copying an existing Builder */
+  public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder(org.apache.avro.FooBarSpecificRecord.Builder other) {
+    return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+  }
+  
+  /** Creates a new FooBarSpecificRecord RecordBuilder by copying an existing FooBarSpecificRecord instance */
+  public static org.apache.avro.FooBarSpecificRecord.Builder newBuilder(org.apache.avro.FooBarSpecificRecord other) {
+    return new org.apache.avro.FooBarSpecificRecord.Builder(other);
+  }
+  
+  /**
+   * RecordBuilder for FooBarSpecificRecord instances.
+   */
+  public static class Builder extends org.apache.avro.specific.SpecificRecordBuilderBase<FooBarSpecificRecord>
+    implements org.apache.avro.data.RecordBuilder<FooBarSpecificRecord> {
+
+    private int id;
+    private java.util.List<java.lang.Integer> relatedids;
+
+    /** Creates a new Builder */
+    private Builder() {
+      super(org.apache.avro.FooBarSpecificRecord.SCHEMA$);
+    }
+    
+    /** Creates a Builder by copying an existing Builder */
+    private Builder(org.apache.avro.FooBarSpecificRecord.Builder other) {
+      super(other);
+    }
+    
+    /** Creates a Builder by copying an existing FooBarSpecificRecord instance */
+    private Builder(org.apache.avro.FooBarSpecificRecord other) {
+            super(org.apache.avro.FooBarSpecificRecord.SCHEMA$);
+      if (isValidValue(fields()[0], other.id)) {
+        this.id = (java.lang.Integer) data().deepCopy(fields()[0].schema(), other.id);
+        fieldSetFlags()[0] = true;
+      }
+      if (isValidValue(fields()[1], other.relatedids)) {
+        this.relatedids = (java.util.List<java.lang.Integer>) data().deepCopy(fields()[1].schema(), other.relatedids);
+        fieldSetFlags()[1] = true;
+      }
+    }
+
+    /** Gets the value of the 'id' field */
+    public java.lang.Integer getId() {
+      return id;
+    }
+    
+    /** Sets the value of the 'id' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder setId(int value) {
+      validate(fields()[0], value);
+      this.id = value;
+      fieldSetFlags()[0] = true;
+      return this; 
+    }
+    
+    /** Checks whether the 'id' field has been set */
+    public boolean hasId() {
+      return fieldSetFlags()[0];
+    }
+    
+    /** Clears the value of the 'id' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder clearId() {
+      fieldSetFlags()[0] = false;
+      return this;
+    }
+
+    /** Gets the value of the 'relatedids' field */
+    public java.util.List<java.lang.Integer> getRelatedids() {
+      return relatedids;
+    }
+    
+    /** Sets the value of the 'relatedids' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder setRelatedids(java.util.List<java.lang.Integer> value) {
+      validate(fields()[1], value);
+      this.relatedids = value;
+      fieldSetFlags()[1] = true;
+      return this; 
+    }
+    
+    /** Checks whether the 'relatedids' field has been set */
+    public boolean hasRelatedids() {
+      return fieldSetFlags()[1];
+    }
+    
+    /** Clears the value of the 'relatedids' field */
+    public org.apache.avro.FooBarSpecificRecord.Builder clearRelatedids() {
+      relatedids = null;
+      fieldSetFlags()[1] = false;
+      return this;
+    }
+
+    @Override
+    public FooBarSpecificRecord build() {
+      try {
+        FooBarSpecificRecord record = new FooBarSpecificRecord();
+        record.id = fieldSetFlags()[0] ? this.id : (java.lang.Integer) defaultValue(fields()[0]);
+        record.relatedids = fieldSetFlags()[1] ? this.relatedids : (java.util.List<java.lang.Integer>) defaultValue(fields()[1]);
+        return record;
+      } catch (Exception e) {
+        throw new org.apache.avro.AvroRuntimeException(e);
+      }
+    }
+  }
+}

Propchange: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/FooBarSpecificRecord.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java?rev=1339864&r1=1339863&r2=1339864&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java Thu May 17 21:12:43 2012
@@ -145,7 +145,7 @@ public class TestReflect {
 
   @Test public void testArray() throws Exception {
     check(R1.class.getDeclaredField("arrayField").getGenericType(),
-          "{\"type\":\"array\",\"items\":\"string\"}");
+          "{\"type\":\"array\",\"items\":\"string\",\"java-class\":\"[Ljava.lang.String;\"}");
   }
   @Test public void testList() throws Exception {
     check(R1.class.getDeclaredField("listField").getGenericType(),

Added: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java?rev=1339864&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java (added)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java Thu May 17 21:12:43 2012
@@ -0,0 +1,179 @@
+package org.apache.avro.reflect;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.avro.FooBarSpecificRecord;
+import org.apache.avro.io.Decoder;
+import org.apache.avro.io.DecoderFactory;
+import org.apache.avro.io.Encoder;
+import org.apache.avro.io.EncoderFactory;
+import org.apache.avro.specific.TestSpecificDatumReader;
+import org.junit.Test;
+
+public class TestReflectDatumReader {
+
+  @Test
+  public void testRead_SpecificDataRecord() throws IOException {
+    FooBarSpecificRecord specificRecord = FooBarSpecificRecord.newBuilder().setId(42)
+        .setRelatedids(Arrays.asList(1, 2, 3)).build();
+    byte[] specificRecordBytes = TestSpecificDatumReader.serializeRecord(specificRecord);
+
+    Decoder decoder = DecoderFactory.get().binaryDecoder(specificRecordBytes, null);
+    ReflectDatumReader<FooBarSpecificRecord> reflectDatumReader = new ReflectDatumReader<FooBarSpecificRecord>(
+        FooBarSpecificRecord.class);
+
+    FooBarSpecificRecord deserialized = new FooBarSpecificRecord();
+    reflectDatumReader.read(deserialized, decoder);
+
+    assertEquals(specificRecord, deserialized);
+  }
+
+  private static <T> byte[] serializeWithReflectDatumWriter(T toSerialize, Class<T> toSerializeClass)
+      throws IOException {
+    ReflectDatumWriter<T> datumWriter = new ReflectDatumWriter<T>(toSerializeClass);
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    Encoder encoder = EncoderFactory.get().binaryEncoder(byteArrayOutputStream, null);
+    datumWriter.write(toSerialize, encoder);
+    encoder.flush();
+    return byteArrayOutputStream.toByteArray();
+  }
+
+  @Test
+  public void testRead_PojoWithList() throws IOException {
+    PojoWithList pojoWithList = new PojoWithList();
+    pojoWithList.setId(42);
+    pojoWithList.setRelatedIds(Arrays.asList(1, 2, 3));
+
+    byte[] serializedBytes = serializeWithReflectDatumWriter(pojoWithList, PojoWithList.class);
+
+    Decoder decoder = DecoderFactory.get().binaryDecoder(serializedBytes, null);
+    ReflectDatumReader<PojoWithList> reflectDatumReader = new ReflectDatumReader<PojoWithList>(
+        PojoWithList.class);
+
+    PojoWithList deserialized = new PojoWithList();
+    reflectDatumReader.read(deserialized, decoder);
+
+    assertEquals(pojoWithList, deserialized);
+
+  }
+
+  @Test
+  public void testRead_PojoWithArray() throws IOException {
+    PojoWithArray pojoWithArray = new PojoWithArray();
+    pojoWithArray.setId(42);
+    pojoWithArray.setRelatedIds(new int[] { 1, 2, 3 });
+
+    byte[] serializedBytes = serializeWithReflectDatumWriter(pojoWithArray, PojoWithArray.class);
+
+    Decoder decoder = DecoderFactory.get().binaryDecoder(serializedBytes, null);
+    ReflectDatumReader<PojoWithArray> reflectDatumReader = new ReflectDatumReader<PojoWithArray>(
+        PojoWithArray.class);
+
+    PojoWithArray deserialized = new PojoWithArray();
+    reflectDatumReader.read(deserialized, decoder);
+
+    assertEquals(pojoWithArray, deserialized);
+  }
+
+  public static class PojoWithList {
+    private int id;
+    private List<Integer> relatedIds;
+
+    public int getId() {
+      return id;
+    }
+
+    public void setId(int id) {
+      this.id = id;
+    }
+
+    public List<Integer> getRelatedIds() {
+      return relatedIds;
+    }
+
+    public void setRelatedIds(List<Integer> relatedIds) {
+      this.relatedIds = relatedIds;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + id;
+      result = prime * result + ((relatedIds == null) ? 0 : relatedIds.hashCode());
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      PojoWithList other = (PojoWithList) obj;
+      if (id != other.id)
+        return false;
+      if (relatedIds == null) {
+        if (other.relatedIds != null)
+          return false;
+      } else if (!relatedIds.equals(other.relatedIds))
+        return false;
+      return true;
+    }
+  }
+
+  public static class PojoWithArray {
+    private int id;
+    private int[] relatedIds;
+
+    public int getId() {
+      return id;
+    }
+
+    public void setId(int id) {
+      this.id = id;
+    }
+
+    public int[] getRelatedIds() {
+      return relatedIds;
+    }
+
+    public void setRelatedIds(int[] relatedIds) {
+      this.relatedIds = relatedIds;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+      result = prime * result + id;
+      result = prime * result + Arrays.hashCode(relatedIds);
+      return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      PojoWithArray other = (PojoWithArray) obj;
+      if (id != other.id)
+        return false;
+      if (!Arrays.equals(relatedIds, other.relatedIds))
+        return false;
+      return true;
+    }
+
+  }
+}

Propchange: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflectDatumReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java?rev=1339864&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java (added)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java Thu May 17 21:12:43 2012
@@ -0,0 +1,47 @@
+package org.apache.avro.specific;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.apache.avro.FooBarSpecificRecord;
+import org.apache.avro.FooBarSpecificRecord.Builder;
+import org.apache.avro.io.Decoder;
+import org.apache.avro.io.DecoderFactory;
+import org.apache.avro.io.Encoder;
+import org.apache.avro.io.EncoderFactory;
+import org.junit.Test;
+
+public class TestSpecificDatumReader {
+
+  public static byte[] serializeRecord(FooBarSpecificRecord fooBarSpecificRecord) throws IOException {
+    SpecificDatumWriter<FooBarSpecificRecord> datumWriter = 
+        new SpecificDatumWriter<FooBarSpecificRecord>(FooBarSpecificRecord.SCHEMA$);
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    Encoder encoder = EncoderFactory.get().binaryEncoder(byteArrayOutputStream, null);
+    datumWriter.write(fooBarSpecificRecord, encoder);
+    encoder.flush();
+    return byteArrayOutputStream.toByteArray();
+  }
+
+  @Test
+  public void testRead() throws IOException {
+    Builder newBuilder = FooBarSpecificRecord.newBuilder();
+    newBuilder.setId(42);
+    newBuilder.setRelatedids(Arrays.asList(1,2,3));
+    FooBarSpecificRecord specificRecord = newBuilder.build();
+    
+    byte[] recordBytes = serializeRecord(specificRecord);
+    
+    Decoder decoder = DecoderFactory.get().binaryDecoder(recordBytes, null);
+    SpecificDatumReader<FooBarSpecificRecord> specificDatumReader = new SpecificDatumReader<FooBarSpecificRecord>(FooBarSpecificRecord.SCHEMA$);
+    FooBarSpecificRecord deserialized = new FooBarSpecificRecord();
+    specificDatumReader.read(deserialized, decoder);
+    
+    assertEquals(specificRecord, deserialized);
+        
+  }
+
+}

Propchange: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/specific/TestSpecificDatumReader.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: avro/trunk/lang/java/avro/src/test/resources/FooBarSpecificRecord.avsc
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/resources/FooBarSpecificRecord.avsc?rev=1339864&view=auto
==============================================================================
--- avro/trunk/lang/java/avro/src/test/resources/FooBarSpecificRecord.avsc (added)
+++ avro/trunk/lang/java/avro/src/test/resources/FooBarSpecificRecord.avsc Thu May 17 21:12:43 2012
@@ -0,0 +1,10 @@
+{
+    "type": "record",
+    "name": "FooBarSpecificRecord",
+    "namespace": "org.apache.avro",
+    "fields": [
+        {"name": "id", "type": "int"},
+        {"name": "relatedids", "type": 
+            {"type": "array", "items": "int"}}
+    ]
+}