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/03/04 00:27:49 UTC
svn commit: r918770 - in /hadoop/avro/trunk: ./
lang/java/src/java/org/apache/avro/reflect/
lang/java/src/java/org/apache/avro/specific/
lang/java/src/test/java/org/apache/avro/
Author: cutting
Date: Wed Mar 3 23:27:48 2010
New Revision: 918770
URL: http://svn.apache.org/viewvc?rev=918770&view=rev
Log:
AVRO-432. Add @Nullable annotation to Java reflect API.
Added:
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/Nullable.java
Modified:
hadoop/avro/trunk/CHANGES.txt
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/ReflectData.java
hadoop/avro/trunk/lang/java/src/java/org/apache/avro/specific/SpecificData.java
hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/TestReflect.java
Modified: hadoop/avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/CHANGES.txt?rev=918770&r1=918769&r2=918770&view=diff
==============================================================================
--- hadoop/avro/trunk/CHANGES.txt (original)
+++ hadoop/avro/trunk/CHANGES.txt Wed Mar 3 23:27:48 2010
@@ -2,6 +2,10 @@
Avro 1.3.1 (unreleased)
+ NEW FEATURES
+
+ AVRO-432. Add @Nullable annotation to Java reflect API. (cutting)
+
IMPROVEMENTS
AVRO-426. Include a ruby gem in distributions.
Added: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/Nullable.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/Nullable.java?rev=918770&view=auto
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/Nullable.java (added)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/Nullable.java Wed Mar 3 23:27:48 2010
@@ -0,0 +1,33 @@
+/**
+ * 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.reflect;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** Declares that null is a valid value for a Java type. Causes an Avro union
+ * with null to be used. May be applied to parameters, fields and methods (to
+ * declare the return type).
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD})
+@Documented
+public @interface Nullable {}
Modified: hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/ReflectData.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/ReflectData.java?rev=918770&r1=918769&r2=918770&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/ReflectData.java (original)
+++ hadoop/avro/trunk/lang/java/src/java/org/apache/avro/reflect/ReflectData.java Wed Mar 3 23:27:48 2010
@@ -61,9 +61,7 @@
protected Schema createFieldSchema(Field field, Map<String, Schema> names) {
Schema schema = super.createFieldSchema(field, names);
- return Schema.createUnion(Arrays.asList(new Schema[] {
- schema,
- Schema.create(Schema.Type.NULL) }));
+ return makeNullable(schema);
}
}
@@ -310,6 +308,12 @@
return Schema.createUnion(branches);
}
+ /** Create and return a union of the null schema and the provided schema. */
+ public static Schema makeNullable(Schema schema) {
+ return Schema.createUnion(Arrays.asList(Schema.create(Schema.Type.NULL),
+ schema));
+ }
+
// Return of this class and its superclasses to serialize.
// Not cached, since this is only used to create schemas, which are cached.
private Collection<Field> getFields(Class recordClass) {
@@ -329,7 +333,10 @@
/** Create a schema for a field. */
protected Schema createFieldSchema(Field field, Map<String, Schema> names) {
- return createSchema(field.getGenericType(), names);
+ Schema schema = createSchema(field.getGenericType(), names);
+ if (field.isAnnotationPresent(Nullable.class)) // nullable
+ schema = makeNullable(schema);
+ return schema;
}
/** Return the protocol for a Java interface.
@@ -365,12 +372,12 @@
Type[] paramTypes = method.getGenericParameterTypes();
Annotation[][] annotations = method.getParameterAnnotations();
for (int i = 0; i < paramTypes.length; i++) {
- Schema paramSchema = null;
+ Schema paramSchema = getSchema(paramTypes[i], names);
for (int j = 0; j < annotations[i].length; j++)
if (annotations[i][j] instanceof Union)
paramSchema = getAnnotatedUnion(((Union)annotations[i][j]), names);
- if (paramSchema == null)
- paramSchema = getSchema(paramTypes[i], names);
+ else if (annotations[i][j] instanceof Nullable)
+ paramSchema = makeNullable(paramSchema);
String paramName = paramNames.length == paramTypes.length
? paramNames[i]
: paramSchema.getName()+i;
@@ -383,6 +390,8 @@
Schema response = union == null
? getSchema(method.getGenericReturnType(), names)
: getAnnotatedUnion(union, names);
+ if (method.isAnnotationPresent(Nullable.class)) // nullable
+ response = makeNullable(response);
List<Schema> errs = new ArrayList<Schema>();
errs.add(Protocol.SYSTEM_ERROR); // every method can throw
@@ -408,5 +417,4 @@
throw new UnsupportedOperationException();
}
-
}
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=918770&r1=918769&r2=918770&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 Wed Mar 3 23:27:48 2010
@@ -157,7 +157,6 @@
ParameterizedType ptype = (ParameterizedType)type;
Class raw = (Class)ptype.getRawType();
java.lang.reflect.Type[] params = ptype.getActualTypeArguments();
- for (int i = 0; i < params.length; i++)
if (GenericArray.class.isAssignableFrom(raw)) { // array
if (params.length != 1)
throw new AvroTypeException("No array type specified.");
@@ -168,6 +167,8 @@
if (!(key == Utf8.class))
throw new AvroTypeException("Map key class not Utf8: "+key);
return Schema.createMap(createSchema(value, names));
+ } else {
+ return createSchema(raw, names);
}
} else if (type instanceof Class) { // class
Class c = (Class)type;
Modified: hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/TestReflect.java
URL: http://svn.apache.org/viewvc/hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/TestReflect.java?rev=918770&r1=918769&r2=918770&view=diff
==============================================================================
--- hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/TestReflect.java (original)
+++ hadoop/avro/trunk/lang/java/src/test/java/org/apache/avro/TestReflect.java Wed Mar 3 23:27:48 2010
@@ -40,6 +40,7 @@
import org.apache.avro.reflect.ReflectDatumReader;
import org.apache.avro.reflect.ReflectDatumWriter;
import org.apache.avro.reflect.Stringable;
+import org.apache.avro.reflect.Nullable;
import org.apache.avro.reflect.Union;
import org.junit.Test;
@@ -268,6 +269,57 @@
checkReadWrite(new R10("foo"), r10Schema);
}
+ // test Nullable annotation on field
+ public static class R11 {
+ @Nullable private String text;
+ public boolean equals(Object o) {
+ if (!(o instanceof R11)) return false;
+ R11 that = (R11)o;
+ if (this.text == null) return that.text == null;
+ return this.text.equals(that.text);
+ }
+ }
+
+ @Test public void testR11() throws Exception {
+ Schema r11Record = ReflectData.get().getSchema(R11.class);
+ assertEquals(Schema.Type.RECORD, r11Record.getType());
+ Schema r11Field = r11Record.getField("text").schema();
+ assertEquals(Schema.Type.UNION, r11Field.getType());
+ assertEquals(Schema.Type.NULL, r11Field.getTypes().get(0).getType());
+ Schema r11String = r11Field.getTypes().get(1);
+ assertEquals(Schema.Type.STRING, r11String.getType());
+ R11 r11 = new R11();
+ checkReadWrite(r11, r11Record);
+ r11.text = "foo";
+ checkReadWrite(r11, r11Record);
+ }
+
+ // test nullable annotation on methods and parameters
+ public static interface P1 {
+ @Nullable String foo(@Nullable String s);
+ }
+
+ @Test public void testP1() throws Exception {
+ Protocol p1 = ReflectData.get().getProtocol(P1.class);
+ Protocol.Message message = p1.getMessages().get("foo");
+ // check response schema is union
+ Schema response = message.getResponse();
+ assertEquals(Schema.Type.UNION, response.getType());
+ assertEquals(Schema.Type.NULL, response.getTypes().get(0).getType());
+ assertEquals(Schema.Type.STRING, response.getTypes().get(1).getType());
+ // check request schema is union
+ Schema request = message.getRequest();
+ Field field = request.getField("s");
+ assertNotNull("field 's' should not be null", field);
+ Schema param = field.schema();
+ assertEquals(Schema.Type.UNION, param.getType());
+ assertEquals(Schema.Type.NULL, param.getTypes().get(0).getType());
+ assertEquals(Schema.Type.STRING, param.getTypes().get(1).getType());
+ // check union erasure
+ assertEquals(String.class, ReflectData.get().getClass(response));
+ assertEquals(String.class, ReflectData.get().getClass(param));
+ }
+
void checkReadWrite(Object object) throws Exception {
checkReadWrite(object, ReflectData.get().getSchema(object.getClass()));
}