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 2010/02/02 22:51:50 UTC
svn commit: r905807 - in /hadoop/avro/trunk: ./
lang/java/src/java/org/apache/avro/generic/
lang/java/src/java/org/apache/avro/specific/
lang/java/src/test/java/org/apache/avro/generic/
lang/java/src/test/java/org/apache/avro/specific/
Author: cutting
Date: Tue Feb 2 21:51:49 2010
New Revision: 905807
URL: http://svn.apache.org/viewvc?rev=905807&view=rev
Log:
AVRO-387. Add IndexedRecord interface, so that specific & generic may share #toString(), #hashCode(), #compare(), etc. Also fix toString() and hashCode() to not throw NPE for uninitialized records.
Added:
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java
hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java
Modified:
hadoop/avro/trunk/CHANGES.txt
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java
hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java
Modified: hadoop/avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/CHANGES.txt?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/CHANGES.txt (original)
+++ hadoop/avro/trunk/CHANGES.txt Tue Feb 2 21:51:49 2010
@@ -36,6 +36,11 @@
AVRO-374. Remove and ignore files that are created by autoreconf. (sbanacho)
+ AVRO-387. Add IndexedRecord interface, common to both specific and
+ generic records, so that toString() and hashCode() implementations
+ can be shared. Also fix toString() and hashCode() to not throw
+ NPE for uninitialized records. (cutting)
+
NEW FEATURES
AVRO-151. Validating Avro schema parser for C (massie)
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericData.java Tue Feb 2 21:51:49 2010
@@ -175,8 +175,8 @@
public boolean validate(Schema schema, Object datum) {
switch (schema.getType()) {
case RECORD:
- if (!(datum instanceof GenericRecord)) return false;
- GenericRecord fields = (GenericRecord)datum;
+ if (!(datum instanceof IndexedRecord)) return false;
+ IndexedRecord fields = (IndexedRecord)datum;
for (Map.Entry<String, Field> entry : schema.getFields().entrySet()) {
Field f = entry.getValue();
if (!validate(f.schema(), fields.get(f.pos())))
@@ -225,11 +225,12 @@
toString(datum, buffer);
return buffer.toString();
}
- private void toString(Object datum, StringBuilder buffer) {
- if (datum instanceof GenericRecord) {
+ /** Renders a Java datum as <a href="http://www.json.org/">JSON</a>. */
+ protected void toString(Object datum, StringBuilder buffer) {
+ if (datum instanceof IndexedRecord) {
buffer.append("{");
int count = 0;
- GenericRecord record = (GenericRecord)datum;
+ IndexedRecord record = (IndexedRecord)datum;
for (Map.Entry<String,Field> e :
record.getSchema().getFields().entrySet()) {
toString(e.getKey(), buffer);
@@ -280,8 +281,8 @@
/** Create a schema given an example datum. */
public Schema induce(Object datum) {
- if (datum instanceof GenericRecord) {
- return ((GenericRecord)datum).getSchema();
+ if (datum instanceof IndexedRecord) {
+ return ((IndexedRecord)datum).getSchema();
} else if (datum instanceof GenericArray) {
Schema elementType = null;
for (Object element : (GenericArray)datum) {
@@ -370,11 +371,11 @@
/** Called by the default implementation of {@link #instanceOf}.*/
protected boolean isRecord(Object datum) {
- return datum instanceof GenericRecord;
+ return datum instanceof IndexedRecord;
}
/** Called to obtain the schema of a record. By default calls
- * {GenericRecord#getSchema(). May be overridden for alternate record
+ * {GenericContainer#getSchema(). May be overridden for alternate record
* representations. */
protected Schema getRecordSchema(Object record) {
return ((GenericContainer)record).getSchema();
@@ -387,7 +388,7 @@
/** Called by the default implementation of {@link #instanceOf}.*/
protected boolean isMap(Object datum) {
- return (datum instanceof Map) && (!(datum instanceof GenericRecord));
+ return datum instanceof Map;
}
/** Called by the default implementation of {@link #instanceOf}.*/
@@ -408,10 +409,11 @@
/** Compute a hash code according to a schema, consistent with {@link
* #compare(Object,Object,Schema)}. */
public int hashCode(Object o, Schema s) {
+ if (o == null) return 0; // incomplete datum
int hashCode = 1;
switch (s.getType()) {
case RECORD:
- GenericRecord r = (GenericRecord)o;
+ IndexedRecord r = (IndexedRecord)o;
for (Map.Entry<String, Field> e : s.getFields().entrySet()) {
Field f = e.getValue();
if (f.order() == Field.Order.IGNORE)
@@ -430,7 +432,7 @@
case NULL:
return 0;
default:
- return (o == null) ? 0 : o.hashCode();
+ return o.hashCode();
}
}
@@ -448,8 +450,8 @@
if (o1 == o2) return 0;
switch (s.getType()) {
case RECORD:
- GenericRecord r1 = (GenericRecord)o1;
- GenericRecord r2 = (GenericRecord)o2;
+ IndexedRecord r1 = (IndexedRecord)o1;
+ IndexedRecord r2 = (IndexedRecord)o2;
for (Map.Entry<String, Field> e : s.getFields().entrySet()) {
Field f = e.getValue();
if (f.order() == Field.Order.IGNORE)
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumReader.java Tue Feb 2 21:51:49 2010
@@ -174,16 +174,16 @@
/** Called by the default implementation of {@link #readRecord} to set a
* record fields value to a record instance. The default implementation is
- * for {@link GenericRecord}.*/
+ * for {@link IndexedRecord}.*/
protected void setField(Object record, String name, int position, Object o) {
- ((GenericRecord)record).put(position, o);
+ ((IndexedRecord)record).put(position, o);
}
/** Called by the default implementation of {@link #readRecord} to retrieve a
* record field value from a reused instance. The default implementation is
- * for {@link GenericRecord}.*/
+ * for {@link IndexedRecord}.*/
protected Object getField(Object record, String name, int position) {
- return ((GenericRecord)record).get(position);
+ return ((IndexedRecord)record).get(position);
}
/** Called by the default implementation of {@link #readRecord} to construct
@@ -359,8 +359,8 @@
* a {@link GenericData.Record}.
*/
protected Object newRecord(Object old, Schema schema) {
- if (old instanceof GenericRecord) {
- GenericRecord record = (GenericRecord)old;
+ if (old instanceof IndexedRecord) {
+ IndexedRecord record = (IndexedRecord)old;
if (record.getSchema() == schema)
return record;
}
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericDatumWriter.java Tue Feb 2 21:51:49 2010
@@ -93,9 +93,9 @@
/** Called by the default implementation of {@link #writeRecord} to retrieve
* a record field value. The default implementation is for {@link
- * GenericRecord}.*/
+ * IndexedRecord}.*/
protected Object getField(Object record, String field, int position) {
- return ((GenericRecord) record).get(position);
+ return ((IndexedRecord) record).get(position);
}
/** Called to write an enum value. May be overridden for alternate enum
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/GenericRecord.java Tue Feb 2 21:51:49 2010
@@ -17,14 +17,11 @@
*/
package org.apache.avro.generic;
-/** An instance of a record schema.*/
-public interface GenericRecord extends GenericContainer {
+/** A generic instance of a record schema. Fields are accessible by name as
+ * well as by index. */
+public interface GenericRecord extends IndexedRecord {
/** Set the value of a field given its name. */
void put(String key, Object v);
- /** Set the value of a field given its position in the schema. */
- void put(int i, Object v);
/** Return the value of a field given its name. */
Object get(String key);
- /** Return the value of a field given its position in the schema. */
- Object get(int i);
}
Added: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java?rev=905807&view=auto
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java (added)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/generic/IndexedRecord.java Tue Feb 2 21:51:49 2010
@@ -0,0 +1,26 @@
+/**
+ * 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.generic;
+
+/** A record implementation that permits field access by integer index.*/
+public interface IndexedRecord extends GenericContainer {
+ /** Set the value of a field given its position in the schema. */
+ void put(int i, Object v);
+ /** Return the value of a field given its position in the schema. */
+ Object get(int i);
+}
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificCompiler.java Tue Feb 2 21:51:49 2010
@@ -275,7 +275,7 @@
line(out, 1, "}");
// set method
line(out, 1, "@SuppressWarnings(value=\"unchecked\")");
- line(out, 1, "public void set(int field$, java.lang.Object value$) {");
+ line(out, 1, "public void put(int field$, java.lang.Object value$) {");
line(out, 2, "switch (field$) {");
i = 0;
for (Map.Entry<String, Schema> field : schema.getFieldSchemas())
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java Tue Feb 2 21:51:49 2010
@@ -17,7 +17,6 @@
*/
package org.apache.avro.specific;
-import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.util.WeakHashMap;
@@ -30,7 +29,6 @@
import org.apache.avro.Protocol;
import org.apache.avro.AvroRuntimeException;
import org.apache.avro.AvroTypeException;
-import org.apache.avro.Schema.Field;
import org.apache.avro.Schema.Type;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericArray;
@@ -64,15 +62,6 @@
@Override
public boolean validate(Schema schema, Object datum) {
switch (schema.getType()) {
- case RECORD:
- Class c = datum.getClass();
- if (!(datum instanceof SpecificRecord)) return false;
- SpecificRecord record = (SpecificRecord)datum;
- Iterator<Field> fields = schema.getFields().values().iterator();
- for (int i = 0; fields.hasNext(); i++)
- if (!validate(fields.next().schema(), record.get(i)))
- return false;
- return true;
case ENUM:
return datum instanceof Enum
&& schema.getEnumSymbols().contains(((Enum)datum).name());
@@ -210,40 +199,8 @@
}
@Override
- public int hashCode(Object o, Schema s) {
- switch (s.getType()) {
- case RECORD:
- int hashCode = 1;
- SpecificRecord r = (SpecificRecord)o;
- Iterator<Field> fields = s.getFields().values().iterator();
- for (int i = 0; fields.hasNext(); i++) {
- Field f = fields.next();
- if (f.order() == Field.Order.IGNORE)
- continue;
- hashCode = hashCodeAdd(hashCode, r.get(i), f.schema());
- }
- return hashCode;
- default:
- return super.hashCode(o, s);
- }
- }
-
- @Override
public int compare(Object o1, Object o2, Schema s) {
switch (s.getType()) {
- case RECORD:
- SpecificRecord r1 = (SpecificRecord)o1;
- SpecificRecord r2 = (SpecificRecord)o2;
- Iterator<Field> fields = s.getFields().values().iterator();
- for (int i = 0; fields.hasNext(); i++) {
- Field f = fields.next();
- if (f.order() == Field.Order.IGNORE)
- continue; // ignore this field
- int compare = compare(r1.get(i), r2.get(i), f.schema());
- if (compare != 0) // not equal
- return f.order() == Field.Order.DESCENDING ? -compare : compare;
- }
- return 0;
case ENUM:
return ((Enum)o1).ordinal() - ((Enum)o2).ordinal();
default:
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificDatumReader.java Tue Feb 2 21:51:49 2010
@@ -44,7 +44,7 @@
@Override
protected void setField(Object record, String name, int position, Object o) {
- ((SpecificRecord)record).set(position, o);
+ ((SpecificRecord)record).put(position, o);
}
@Override
protected Object getField(Object record, String name, int position) {
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificExceptionBase.java Tue Feb 2 21:51:49 2010
@@ -27,7 +27,7 @@
public abstract Schema getSchema();
public abstract Object get(int field);
- public abstract void set(int field, Object value);
+ public abstract void put(int field, Object value);
public boolean equals(Object that) {
if (that == this) return true; // identical object
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecord.java Tue Feb 2 21:51:49 2010
@@ -17,12 +17,10 @@
*/
package org.apache.avro.specific;
-import org.apache.avro.generic.GenericContainer;
+import org.apache.avro.generic.IndexedRecord;
/** Implemented by generated record classes. Permits efficient access to
* fields.*/
-public interface SpecificRecord extends GenericContainer {
- Object get(int field);
- void set(int field, Object value);
+public interface SpecificRecord extends IndexedRecord {
}
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificRecordBase.java Tue Feb 2 21:51:49 2010
@@ -25,7 +25,7 @@
public abstract Schema getSchema();
public abstract Object get(int field);
- public abstract void set(int field, Object value);
+ public abstract void put(int field, Object value);
@Override
public boolean equals(Object that) {
@@ -45,5 +45,10 @@
return SpecificData.get().compare(this, that, this.getSchema());
}
+ @Override
+ public String toString() {
+ return SpecificData.get().toString(this);
+ }
+
}
Modified: hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java?rev=905807&r1=905806&r2=905807&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java (original)
+++ hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/generic/TestGenericData.java Tue Feb 2 21:51:49 2010
@@ -19,8 +19,11 @@
import static org.junit.Assert.*;
+import java.util.Arrays;
+
import org.apache.avro.Schema;
import org.apache.avro.AvroRuntimeException;
+import org.apache.avro.Schema.Type;
import org.junit.Test;
@@ -45,5 +48,13 @@
public void testArrayConstructorWrongSchema() throws Exception {
new GenericData.Array<Object>(1, Schema.create(Schema.Type.INT));
}
+
+ @Test
+ /** Make sure that even with nulls, hashCode() doesn't throw NPE. */
+ public void testHashCode() {
+ GenericData.get().hashCode(null, Schema.create(Type.NULL));
+ GenericData.get().hashCode(null, Schema.createUnion(
+ Arrays.asList(Schema.create(Type.BOOLEAN), Schema.create(Type.STRING))));
+ }
}
Added: hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java?rev=905807&view=auto
==============================================================================
--- hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java (added)
+++ hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/specific/TestSpecificData.java Tue Feb 2 21:51:49 2010
@@ -0,0 +1,41 @@
+/**
+ * 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.specific;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+import org.apache.avro.test.TestRecord;
+
+public class TestSpecificData {
+
+ @Test
+ /** Make sure that even with nulls, hashCode() doesn't throw NPE. */
+ public void testHashCode() {
+ new TestRecord().hashCode();
+ SpecificData.get().hashCode(null, TestRecord.SCHEMA$);
+ }
+
+ @Test
+ /** Make sure that even with nulls, toString() doesn't throw NPE. */
+ public void testToString() {
+ new TestRecord().toString();
+ }
+
+}