avro-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cutt...@apache.org
Subject svn commit: r1178973 [1/3] - in /avro/trunk: ./ lang/java/ lang/java/avro/src/main/java/org/apache/avro/generic/ lang/java/thrift/ lang/java/thrift/src/ lang/java/thrift/src/main/ lang/java/thrift/src/main/java/ lang/java/thrift/src/main/java/org/ lang...
Date Tue, 04 Oct 2011 21:54:26 GMT
Author: cutting
Date: Tue Oct  4 21:54:25 2011
New Revision: 1178973

URL: http://svn.apache.org/viewvc?rev=1178973&view=rev
Log:
AVRO-804. Java: Add support for reading and writing instances of Thrift generated classes.

Added:
    avro/trunk/lang/java/thrift/   (with props)
    avro/trunk/lang/java/thrift/pom.xml
    avro/trunk/lang/java/thrift/src/
    avro/trunk/lang/java/thrift/src/main/
    avro/trunk/lang/java/thrift/src/main/java/
    avro/trunk/lang/java/thrift/src/main/java/org/
    avro/trunk/lang/java/thrift/src/main/java/org/apache/
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftData.java
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumReader.java
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumWriter.java
    avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/package.html
    avro/trunk/lang/java/thrift/src/test/
    avro/trunk/lang/java/thrift/src/test/java/
    avro/trunk/lang/java/thrift/src/test/java/org/
    avro/trunk/lang/java/thrift/src/test/java/org/apache/
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/TestThrift.java
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/E.java
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Error.java
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Foo.java
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Nested.java
    avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Test.java
    avro/trunk/lang/java/thrift/src/test/thrift/
    avro/trunk/lang/java/thrift/src/test/thrift/test.thrift
Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumWriter.java
    avro/trunk/lang/java/pom.xml

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1178973&r1=1178972&r2=1178973&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Tue Oct  4 21:54:25 2011
@@ -28,6 +28,11 @@ Avro 1.6.0 (unreleased)
     AVRO-890: Java: Add Maven archetype for creating Avro service
     projects.  (Stephen Gargan via cutting)
 
+    AVRO-804. Java: Add support for reading and writing instances of
+    Thrift generated classes.  This permits Thrift-defined data
+    structures to be written and read from Avro-format data files.
+    (cutting)
+
   OPTIMIZATIONS
 
     AVRO-853: Java: Cache Schema hash codes. (cutting)

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java?rev=1178973&r1=1178972&r2=1178973&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java (original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericData.java Tue Oct
 4 21:54:25 2011
@@ -510,6 +510,21 @@ public class GenericData {
     return ((IndexedRecord)record).get(position);
   }
 
+  /** Produce state for repeated calls to {@link
+   * #getField(Object,String,int,Object)} and {@link
+   * #setField(Object,String,int,Object,Object)} on the same record.*/
+  protected Object getRecordState(Schema schema) { return null; }
+
+  /** Version of {@link #setField} that has state. */
+  protected void setField(Object r, String n, int p, Object o, Object state) {
+    setField(r, n, p, o);
+  }
+  
+  /** Version of {@link #getField} that has state. */
+  protected Object getField(Object record, String name, int pos, Object state) {
+    return getField(record, name, pos);
+  }
+
   /** Return the index for a datum within a union.  Implemented with {@link
    * #instanceOf(Schema,Object)}.*/
   public int resolveUnion(Schema union, Object datum) {

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java?rev=1178973&r1=1178972&r2=1178973&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
(original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumReader.java
Tue Oct  4 21:54:25 2011
@@ -163,16 +163,17 @@ public class GenericDatumReader<D> imple
    * representations.*/
   protected Object readRecord(Object old, Schema expected, 
       ResolvingDecoder in) throws IOException {
-    Object record = data.newRecord(old, expected);
+    Object r = data.newRecord(old, expected);
+    Object state = data.getRecordState(expected);
     
     for (Field f : in.readFieldOrder()) {
       int pos = f.pos();
       String name = f.name();
-      Object oldDatum = (old != null) ? data.getField(record, name, pos) : null;
-      data.setField(record, name, pos, read(oldDatum, f.schema(), in));
+      Object oldDatum = (old!=null) ? data.getField(r, name, pos, state) : null;
+      data.setField(r, name, pos, read(oldDatum, f.schema(), in), state);
     }
 
-    return record;
+    return r;
   }
   
   /** Called to read an enum value. May be overridden for alternate enum

Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumWriter.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumWriter.java?rev=1178973&r1=1178972&r2=1178973&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumWriter.java
(original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/generic/GenericDatumWriter.java
Tue Oct  4 21:54:25 2011
@@ -74,7 +74,7 @@ public class GenericDatumWriter<D> imple
       case FIXED:   writeFixed(schema, datum, out);   break;
       case STRING:  writeString(schema, datum, out);  break;
       case BYTES:   writeBytes(datum, out);           break;
-      case INT:     out.writeInt((Integer)datum);     break;
+      case INT:     out.writeInt(((Number)datum).intValue()); break;
       case LONG:    out.writeLong((Long)datum);       break;
       case FLOAT:   out.writeFloat((Float)datum);     break;
       case DOUBLE:  out.writeDouble((Double)datum);   break;
@@ -98,8 +98,9 @@ public class GenericDatumWriter<D> imple
    * representations.*/
   protected void writeRecord(Schema schema, Object datum, Encoder out)
     throws IOException {
+    Object state = data.getRecordState(schema);
     for (Field f : schema.getFields()) {
-      Object value = data.getField(datum, f.name(), f.pos());
+      Object value = data.getField(datum, f.name(), f.pos(), state);
       try {
         write(f.schema(), value, out);
       } catch (NullPointerException e) {

Modified: avro/trunk/lang/java/pom.xml
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/pom.xml?rev=1178973&r1=1178972&r2=1178973&view=diff
==============================================================================
--- avro/trunk/lang/java/pom.xml (original)
+++ avro/trunk/lang/java/pom.xml Tue Oct  4 21:54:25 2011
@@ -405,6 +405,7 @@
     <module>tools</module>
     <module>mapred</module>
     <module>protobuf</module>
+    <module>thrift</module>
     <module>archetypes</module>
   </modules>
 

Propchange: avro/trunk/lang/java/thrift/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Tue Oct  4 21:54:25 2011
@@ -0,0 +1 @@
+target

Added: avro/trunk/lang/java/thrift/pom.xml
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/pom.xml?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/pom.xml (added)
+++ avro/trunk/lang/java/thrift/pom.xml Tue Oct  4 21:54:25 2011
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<project
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+  xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>avro-parent</artifactId>
+    <groupId>org.apache.avro</groupId>
+    <version>1.6.0-SNAPSHOT</version>
+    <relativePath>../</relativePath>
+  </parent>
+  <artifactId>avro-thrift</artifactId>
+  <name>Apache Avro Thrift Compatibility</name>
+  <description>Permit serialization of Thrift-generated classes as
+  Avro data.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>avro</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.thrift</groupId>
+      <artifactId>libthrift</artifactId>
+      <version>0.7.0</version>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>thrift-generate</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-antrun-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>generate-test-sources</phase>
+                <configuration>
+                  <tasks>
+                    <mkdir dir="target/thrift-tmp" />
+                    <exec executable="thrift">
+                      <arg value="--gen" /> <arg value="java:beans"/>
+                      <arg value="-o"/>
+                      <arg value="target/thrift-tmp"/>
+                      <arg value="src/test/thrift/test.thrift"/>
+                    </exec>
+                    <copy todir="src/test/java" overwrite="true">
+                      <fileset dir="target/thrift-tmp/gen-javabean" />
+                    </copy>
+                  </tasks>
+                </configuration>
+                <goals>
+                  <goal>run</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+</project>

Added: avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftData.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftData.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftData.java (added)
+++ avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftData.java Tue Oct
 4 21:54:25 2011
@@ -0,0 +1,202 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.avro.thrift;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.avro.Schema;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema.Field;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.specific.SpecificData;
+
+import org.apache.thrift.TBase;
+import org.apache.thrift.TFieldIdEnum;
+import org.apache.thrift.TUnion;
+import org.apache.thrift.protocol.TType;
+import org.apache.thrift.meta_data.FieldMetaData;
+import org.apache.thrift.meta_data.FieldValueMetaData;
+import org.apache.thrift.meta_data.EnumMetaData;
+import org.apache.thrift.meta_data.ListMetaData;
+import org.apache.thrift.meta_data.SetMetaData;
+import org.apache.thrift.meta_data.MapMetaData;
+import org.apache.thrift.meta_data.StructMetaData;
+
+/** Utilities for serializing Thrift data in Avro format. */
+public class ThriftData extends GenericData {
+  static final String THRIFT_TYPE = "thrift";
+  static final String THRIFT_PROP = "thrift";
+
+  private static final ThriftData INSTANCE = new ThriftData();
+
+  protected ThriftData() {}
+  
+  /** Return the singleton instance. */
+  public static ThriftData get() { return INSTANCE; }
+
+  @Override
+  public void setField(Object r, String n, int pos, Object o) {
+    setField(r, n, pos, o, getRecordState(getSchema(r.getClass())));
+  }
+
+  @Override
+  public Object getField(Object r, String name, int pos) {
+    return getField(r, name, pos, getRecordState(getSchema(r.getClass())));
+  }
+
+  @Override
+  protected Object getRecordState(Schema schema) { return getFieldIds(schema); }
+
+  @Override
+  protected void setField(Object r, String n, int pos, Object v, Object state) {
+    ((TBase)r).setFieldValue(((TFieldIdEnum[])state)[pos], v);
+  }
+
+  @Override
+  protected Object getField(Object record, String name, int pos, Object state) {
+    return ((TBase)record).getFieldValue(((TFieldIdEnum[])state)[pos]);
+  }
+
+  private final Map<Schema,TFieldIdEnum[]> fieldCache =
+    new ConcurrentHashMap<Schema,TFieldIdEnum[]>();
+
+  public TFieldIdEnum[] getFieldIds(Schema s) {
+    TFieldIdEnum[] fields = fieldCache.get(s);
+    if (fields == null)
+      try {                                       // cache miss
+        fields = new TFieldIdEnum[s.getFields().size()];
+        Class c = Class.forName(SpecificData.getClassName(s));
+        for (TFieldIdEnum f : FieldMetaData.getStructMetaDataMap(c).keySet())
+          fields[s.getField(f.getFieldName()).pos()] = f;
+        fieldCache.put(s, fields);                  // update cache
+      } catch (ClassNotFoundException e) {
+        throw new AvroRuntimeException(e);
+      }
+    return fields;
+  }
+
+  @Override
+  protected boolean isRecord(Object datum) {
+    return datum instanceof TBase && !(datum instanceof TUnion);
+  }
+
+  @Override
+  public Object newRecord(Object old, Schema schema) {
+    try {
+      Class c = Class.forName(SpecificData.getClassName(schema));
+      if (c == null)
+        return newRecord(old, schema);            // punt to generic
+      if (c.isInstance(old))
+        return old;                               // reuse instance
+      return c.newInstance();                     // create new instance
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  @Override
+  protected Schema getRecordSchema(Object record) {
+    return getSchema(record.getClass());
+  }
+
+  private final Map<Class,Schema> schemaCache
+    = new ConcurrentHashMap<Class,Schema>();
+
+  /** Return a record schema given a thrift generated class. */
+  public Schema getSchema(Class c) {
+    Schema schema = schemaCache.get(c);
+
+    if (schema == null) {                         // cache miss
+      try {
+        schema = Schema.createRecord(c.getName(), null, null,
+                                     Throwable.class.isAssignableFrom(c));
+        List<Field> fields = new ArrayList<Field>();
+        for (FieldMetaData f : FieldMetaData.getStructMetaDataMap(c).values()) {
+          Schema s = getSchema(f.valueMetaData);
+          fields.add(new Field(f.fieldName, s, null, null));
+        }
+        schema.setFields(fields);
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+      schemaCache.put(c, schema);                 // update cache
+    }
+    return schema;
+  }
+
+  private static final Schema NULL = Schema.create(Schema.Type.NULL);
+
+  private Schema getSchema(FieldValueMetaData f) {
+    Schema result;
+    switch (f.type) {
+    case TType.BOOL:
+      return Schema.create(Schema.Type.BOOLEAN);
+    case TType.BYTE:
+      Schema b = Schema.create(Schema.Type.INT);
+      b.addProp(THRIFT_PROP, "byte");
+      return b;
+    case TType.I16:
+      Schema s = Schema.create(Schema.Type.INT);
+      s.addProp(THRIFT_PROP, "short");
+      return s;
+    case TType.I32:
+      return Schema.create(Schema.Type.INT);
+    case TType.I64:
+      return Schema.create(Schema.Type.LONG);
+    case TType.DOUBLE:
+      return Schema.create(Schema.Type.DOUBLE);
+    case TType.ENUM:
+      EnumMetaData enumMeta = (EnumMetaData)f;
+      Class<? extends Enum> c = (Class<? extends Enum>)enumMeta.enumClass;
+      List<String> symbols = new ArrayList<String>();
+      for (Enum e : c.getEnumConstants())
+        symbols.add(e.name());
+      return Schema.createEnum(c.getName(), null, null, symbols);
+    case TType.LIST:
+      ListMetaData listMeta = (ListMetaData)f;
+      return Schema.createArray(getSchema(listMeta.elemMetaData));
+    case TType.MAP:
+      MapMetaData mapMeta = (MapMetaData)f;
+      if (mapMeta.keyMetaData.type != TType.STRING)
+        throw new AvroRuntimeException("Map keys must be strings: "+f);
+      return Schema.createMap(getSchema(mapMeta.valueMetaData));
+    case TType.SET:
+      SetMetaData setMeta = (SetMetaData)f;
+      Schema set = Schema.createArray(getSchema(setMeta.elemMetaData));
+      set.addProp(THRIFT_PROP, "set");
+      return set;
+    case TType.STRING:
+      if (f.isBinary())
+        return Schema.create(Schema.Type.BYTES);
+      else
+        return Schema.create(Schema.Type.STRING);
+    case TType.STRUCT:
+      StructMetaData structMeta = (StructMetaData)f;
+      Schema record = getSchema(structMeta.structClass);
+      return record;
+    case TType.VOID:
+      return Schema.create(Schema.Type.NULL);
+    default:
+      throw new RuntimeException("Unexpected type in field: "+f);
+    }
+  }
+
+}

Added: avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumReader.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumReader.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumReader.java
(added)
+++ avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumReader.java
Tue Oct  4 21:54:25 2011
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.avro.thrift;
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+
+import org.apache.avro.Schema;
+import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.generic.GenericDatumReader;
+import org.apache.avro.specific.SpecificData;
+import org.apache.avro.io.Decoder;
+
+/** {@link org.apache.avro.io.DatumReader DatumReader} for generated Thrift
+ * classes. */
+public class ThriftDatumReader<T> extends GenericDatumReader<T> {
+  public ThriftDatumReader() {
+    this(null, null, ThriftData.get());
+  }
+
+  public ThriftDatumReader(Class<T> c) {
+    this(ThriftData.get().getSchema(c));
+  }
+
+  /** Construct where the writer's and reader's schemas are the same. */
+  public ThriftDatumReader(Schema schema) {
+    this(schema, schema, ThriftData.get());
+  }
+
+  /** Construct given writer's and reader's schema. */
+  public ThriftDatumReader(Schema writer, Schema reader) {
+    this(writer, reader, ThriftData.get());
+  }
+
+  protected ThriftDatumReader(Schema writer, Schema reader, ThriftData data) {
+    super(writer, reader, data);
+  }
+
+  @Override
+  protected Object createEnum(String symbol, Schema schema) {
+    try {
+      Class c = Class.forName(SpecificData.getClassName(schema));
+      if (c == null) return super.createEnum(symbol, schema); // punt to generic
+      return Enum.valueOf(c, symbol);
+    } catch (Exception e) {
+      throw new AvroRuntimeException(e);
+    }
+  }
+
+  @Override
+  protected Object readInt(Object old, Schema s, Decoder in)
+    throws IOException {
+    String type = s.getProp(ThriftData.THRIFT_PROP);
+    int value = in.readInt();
+    if (type != null) {
+      if ("byte".equals(type)) return (byte)value;
+      if ("short".equals(type)) return (short)value;
+    }
+    return value;
+  }
+
+  @Override
+  protected Object readString(Object old, Decoder in) throws IOException {
+    return super.readString(old, in).toString();
+  }    
+
+  @Override
+  protected Object newArray(Object old, int size, Schema schema) {
+    if ("set".equals(schema.getProp(ThriftData.THRIFT_PROP))) {
+      if (old instanceof Set) {
+        ((Set) old).clear();
+        return old;
+      }
+      return new HashSet();
+    } else {
+      return super.newArray(old, size, schema);
+    }
+  }
+
+}

Added: avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumWriter.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumWriter.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumWriter.java
(added)
+++ avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/ThriftDatumWriter.java
Tue Oct  4 21:54:25 2011
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.avro.thrift;
+
+import org.apache.avro.Schema;
+import org.apache.avro.io.Encoder;
+import org.apache.avro.generic.GenericDatumWriter;
+
+import java.nio.ByteBuffer;
+import java.io.IOException;
+
+/** {@link org.apache.avro.io.DatumWriter DatumWriter} for generated thrift
+ * classes. */
+public class ThriftDatumWriter<T> extends GenericDatumWriter<T> {
+  public ThriftDatumWriter() {
+    super(ThriftData.get());
+  }
+
+  public ThriftDatumWriter(Class<T> c) {
+    super(ThriftData.get().getSchema(c), ThriftData.get());
+  }
+  
+  public ThriftDatumWriter(Schema schema) {
+    super(schema, ThriftData.get());
+  }
+  
+  protected ThriftDatumWriter(Schema root, ThriftData thriftData) {
+    super(root, thriftData);
+  }
+  
+  protected ThriftDatumWriter(ThriftData thriftData) {
+    super(thriftData);
+  }
+
+  @Override
+  protected void writeBytes(Object datum, Encoder out) throws IOException {
+    // Thrift assymetry: setter takes ByteBuffer but getter returns byte[]
+    out.writeBytes(ByteBuffer.wrap((byte[])datum));
+  }
+
+
+}
+

Added: avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/package.html
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/package.html?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/package.html (added)
+++ avro/trunk/lang/java/thrift/src/main/java/org/apache/avro/thrift/package.html Tue Oct
 4 21:54:25 2011
@@ -0,0 +1,46 @@
+<html>
+
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+
+<body><a href="http://thrift.apache.org/">Thrift</a> compatibility.
+
+<p>Thrift primitive types are mapped to Avro schemas as follows:</p>
+<table>
+<tr><th>Thrift type</th><th>Avro schema</th></tr>
+<tr><td>bool</td><td>"boolean"</td></tr>
+<tr><td>byte</td><td>{"type": "int", "thrift": "byte"}</td></tr>
+<tr><td>i16</td><td>{"type": "int", "thrift": "short"}</td></tr>
+<tr><td>i32</td><td>"int"</td></tr>
+<tr><td>i64</td><td>"long"</td></tr>
+<tr><td>double</td><td>"double"</td></tr>
+<tr><td>string</td><td>"string"</td></tr>
+<tr><td>binary</td><td>"bytes"</td></tr>
+</table>
+
+<p>Thrift complex types are mapped to Avro complex types as follows:</p>
+<table>
+<tr><th>Thrift</th><th>Avro</th></tr>
+<tr><td>struct</td><td>record</td></tr>
+<tr><td>enum</td><td>enum</td></tr>
+<tr><td>list</td><td>array</td></tr>
+<tr><td>set</td><td>array <em>(Note: "thrift":"set" is added
to schema.)</em></td></tr>
+<tr><td>map</td><td>map <em>(Note: only string keys are permitted.)</em></td></tr>
+</table>
+
+</body>
+</html>

Added: avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/TestThrift.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/TestThrift.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/TestThrift.java (added)
+++ avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/TestThrift.java Tue Oct
 4 21:54:25 2011
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.avro.thrift;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Collections;
+
+import org.apache.avro.io.DecoderFactory;
+import org.apache.avro.io.Encoder;
+import org.apache.avro.io.EncoderFactory;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.avro.thrift.test.Test;
+import org.apache.avro.thrift.test.E;
+import org.apache.avro.thrift.test.Nested;
+
+public class TestThrift {
+
+  @org.junit.Test public void testStruct() throws Exception {
+
+    System.out.println(ThriftData.get().getSchema(Test.class).toString(true));
+
+    Test test = new Test();
+    test.setBoolField(true);
+    test.setByteField((byte)2);
+    test.setI16Field((short)3);
+    test.setI32Field(4);
+    test.setI64Field(5L);
+    test.setDoubleField(2.0);
+    test.setStringField("foo");
+    test.setBinaryField(ByteBuffer.wrap(new byte[] {0,-1}));
+    test.setMapField(Collections.singletonMap("x", 1));
+    test.setListField(Collections.singletonList(7));
+    test.setSetField(Collections.singleton(8));
+    test.setEnumField(E.X);
+    test.setStructField(new Nested(9));
+
+    System.out.println(test);
+
+    ByteArrayOutputStream bao = new ByteArrayOutputStream();
+    ThriftDatumWriter<Test> w = new ThriftDatumWriter<Test>(Test.class);
+    Encoder e = EncoderFactory.get().binaryEncoder(bao, null);
+    w.write(test, e);
+    e.flush();
+    
+    Object o = new ThriftDatumReader<Test>(Test.class).read
+      (null,
+       DecoderFactory.get().createBinaryDecoder
+       (new ByteArrayInputStream(bao.toByteArray()), null));
+
+    assertEquals(test, o);
+
+  }
+}

Added: avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/E.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/E.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/E.java (added)
+++ avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/E.java Tue Oct 
4 21:54:25 2011
@@ -0,0 +1,47 @@
+/**
+ * Autogenerated by Thrift Compiler (0.7.0)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ */
+package org.apache.avro.thrift.test;
+
+
+import java.util.Map;
+import java.util.HashMap;
+import org.apache.thrift.TEnum;
+
+public enum E implements org.apache.thrift.TEnum {
+  X(1),
+  Y(2),
+  Z(3);
+
+  private final int value;
+
+  private E(int value) {
+    this.value = value;
+  }
+
+  /**
+   * Get the integer value of this enum value, as defined in the Thrift IDL.
+   */
+  public int getValue() {
+    return value;
+  }
+
+  /**
+   * Find a the enum type by its integer value, as defined in the Thrift IDL.
+   * @return null if the value is not found.
+   */
+  public static E findByValue(int value) { 
+    switch (value) {
+      case 1:
+        return X;
+      case 2:
+        return Y;
+      case 3:
+        return Z;
+      default:
+        return null;
+    }
+  }
+}

Added: avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Error.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Error.java?rev=1178973&view=auto
==============================================================================
--- avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Error.java (added)
+++ avro/trunk/lang/java/thrift/src/test/java/org/apache/avro/thrift/test/Error.java Tue Oct
 4 21:54:25 2011
@@ -0,0 +1,316 @@
+/**
+ * Autogenerated by Thrift Compiler (0.7.0)
+ *
+ * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
+ */
+package org.apache.avro.thrift.test;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.EnumMap;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.EnumSet;
+import java.util.Collections;
+import java.util.BitSet;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Error extends Exception implements org.apache.thrift.TBase<Error, Error._Fields>,
java.io.Serializable, Cloneable {
+  private static final org.apache.thrift.protocol.TStruct STRUCT_DESC = new org.apache.thrift.protocol.TStruct("Error");
+
+  private static final org.apache.thrift.protocol.TField MESSAGE_FIELD_DESC = new org.apache.thrift.protocol.TField("message",
org.apache.thrift.protocol.TType.STRING, (short)1);
+
+  private String message; // required
+
+  /** The set of fields this struct contains, along with convenience methods for finding
and manipulating them. */
+  public enum _Fields implements org.apache.thrift.TFieldIdEnum {
+    MESSAGE((short)1, "message");
+
+    private static final Map<String, _Fields> byName = new HashMap<String, _Fields>();
+
+    static {
+      for (_Fields field : EnumSet.allOf(_Fields.class)) {
+        byName.put(field.getFieldName(), field);
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, or null if its not found.
+     */
+    public static _Fields findByThriftId(int fieldId) {
+      switch(fieldId) {
+        case 1: // MESSAGE
+          return MESSAGE;
+        default:
+          return null;
+      }
+    }
+
+    /**
+     * Find the _Fields constant that matches fieldId, throwing an exception
+     * if it is not found.
+     */
+    public static _Fields findByThriftIdOrThrow(int fieldId) {
+      _Fields fields = findByThriftId(fieldId);
+      if (fields == null) throw new IllegalArgumentException("Field " + fieldId + " doesn't
exist!");
+      return fields;
+    }
+
+    /**
+     * Find the _Fields constant that matches name, or null if its not found.
+     */
+    public static _Fields findByName(String name) {
+      return byName.get(name);
+    }
+
+    private final short _thriftId;
+    private final String _fieldName;
+
+    _Fields(short thriftId, String fieldName) {
+      _thriftId = thriftId;
+      _fieldName = fieldName;
+    }
+
+    public short getThriftFieldId() {
+      return _thriftId;
+    }
+
+    public String getFieldName() {
+      return _fieldName;
+    }
+  }
+
+  // isset id assignments
+
+  public static final Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> metaDataMap;
+  static {
+    Map<_Fields, org.apache.thrift.meta_data.FieldMetaData> tmpMap = new EnumMap<_Fields,
org.apache.thrift.meta_data.FieldMetaData>(_Fields.class);
+    tmpMap.put(_Fields.MESSAGE, new org.apache.thrift.meta_data.FieldMetaData("message",
org.apache.thrift.TFieldRequirementType.DEFAULT, 
+        new org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));
+    metaDataMap = Collections.unmodifiableMap(tmpMap);
+    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(Error.class, metaDataMap);
+  }
+
+  public Error() {
+  }
+
+  public Error(
+    String message)
+  {
+    this();
+    this.message = message;
+  }
+
+  /**
+   * Performs a deep copy on <i>other</i>.
+   */
+  public Error(Error other) {
+    if (other.isSetMessage()) {
+      this.message = other.message;
+    }
+  }
+
+  public Error deepCopy() {
+    return new Error(this);
+  }
+
+  @Override
+  public void clear() {
+    this.message = null;
+  }
+
+  public String getMessage() {
+    return this.message;
+  }
+
+  public void setMessage(String message) {
+    this.message = message;
+  }
+
+  public void unsetMessage() {
+    this.message = null;
+  }
+
+  /** Returns true if field message is set (has been assigned a value) and false otherwise
*/
+  public boolean isSetMessage() {
+    return this.message != null;
+  }
+
+  public void setMessageIsSet(boolean value) {
+    if (!value) {
+      this.message = null;
+    }
+  }
+
+  public void setFieldValue(_Fields field, Object value) {
+    switch (field) {
+    case MESSAGE:
+      if (value == null) {
+        unsetMessage();
+      } else {
+        setMessage((String)value);
+      }
+      break;
+
+    }
+  }
+
+  public Object getFieldValue(_Fields field) {
+    switch (field) {
+    case MESSAGE:
+      return getMessage();
+
+    }
+    throw new IllegalStateException();
+  }
+
+  /** Returns true if field corresponding to fieldID is set (has been assigned a value) and
false otherwise */
+  public boolean isSet(_Fields field) {
+    if (field == null) {
+      throw new IllegalArgumentException();
+    }
+
+    switch (field) {
+    case MESSAGE:
+      return isSetMessage();
+    }
+    throw new IllegalStateException();
+  }
+
+  @Override
+  public boolean equals(Object that) {
+    if (that == null)
+      return false;
+    if (that instanceof Error)
+      return this.equals((Error)that);
+    return false;
+  }
+
+  public boolean equals(Error that) {
+    if (that == null)
+      return false;
+
+    boolean this_present_message = true && this.isSetMessage();
+    boolean that_present_message = true && that.isSetMessage();
+    if (this_present_message || that_present_message) {
+      if (!(this_present_message && that_present_message))
+        return false;
+      if (!this.message.equals(that.message))
+        return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return 0;
+  }
+
+  public int compareTo(Error other) {
+    if (!getClass().equals(other.getClass())) {
+      return getClass().getName().compareTo(other.getClass().getName());
+    }
+
+    int lastComparison = 0;
+    Error typedOther = (Error)other;
+
+    lastComparison = Boolean.valueOf(isSetMessage()).compareTo(typedOther.isSetMessage());
+    if (lastComparison != 0) {
+      return lastComparison;
+    }
+    if (isSetMessage()) {
+      lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.message, typedOther.message);
+      if (lastComparison != 0) {
+        return lastComparison;
+      }
+    }
+    return 0;
+  }
+
+  public _Fields fieldForId(int fieldId) {
+    return _Fields.findByThriftId(fieldId);
+  }
+
+  public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException
{
+    org.apache.thrift.protocol.TField field;
+    iprot.readStructBegin();
+    while (true)
+    {
+      field = iprot.readFieldBegin();
+      if (field.type == org.apache.thrift.protocol.TType.STOP) { 
+        break;
+      }
+      switch (field.id) {
+        case 1: // MESSAGE
+          if (field.type == org.apache.thrift.protocol.TType.STRING) {
+            this.message = iprot.readString();
+          } else { 
+            org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+          }
+          break;
+        default:
+          org.apache.thrift.protocol.TProtocolUtil.skip(iprot, field.type);
+      }
+      iprot.readFieldEnd();
+    }
+    iprot.readStructEnd();
+    validate();
+  }
+
+  public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException
{
+    validate();
+
+    oprot.writeStructBegin(STRUCT_DESC);
+    if (this.message != null) {
+      oprot.writeFieldBegin(MESSAGE_FIELD_DESC);
+      oprot.writeString(this.message);
+      oprot.writeFieldEnd();
+    }
+    oprot.writeFieldStop();
+    oprot.writeStructEnd();
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder("Error(");
+    boolean first = true;
+
+    sb.append("message:");
+    if (this.message == null) {
+      sb.append("null");
+    } else {
+      sb.append(this.message);
+    }
+    first = false;
+    sb.append(")");
+    return sb.toString();
+  }
+
+  public void validate() throws org.apache.thrift.TException {
+    // check for required fields
+  }
+
+  private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
+    try {
+      write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+  private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException
{
+    try {
+      read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
+    } catch (org.apache.thrift.TException te) {
+      throw new java.io.IOException(te);
+    }
+  }
+
+}
+



Mime
View raw message