Permalink
Browse files

AVRO-1186. Java: Extend specific compiler to emit Java annotations.

git-svn-id: https://svn.apache.org/repos/asf/avro/trunk@1405903 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 3c15fc6 commit 9b9068a00a3a1fac2525fe245365238b58370120 @cutting cutting committed Nov 5, 2012
View
6 CHANGES.txt
@@ -9,6 +9,12 @@ Trunk (not yet released)
AVRO-1157. Java: Extend schema and protocol property support from
string-only to full JSON. (cutting)
+ AVRO-1186. Java: Extend specific compiler to emit Java annotations
+ on interfaces, classes, fields and methods for the property
+ "javaAnnotation". The value of the property may either be a
+ string or a JSON array of strings in order to emit multiple
+ annotations. (cutting)
+
IMPROVEMENTS
AVRO-1169. Java: Reduce memory footprint of resolver.
View
18 lang/java/compiler/src/main/java/org/apache/avro/compiler/specific/SpecificCompiler.java
@@ -37,6 +37,7 @@
import org.apache.avro.Protocol.Message;
import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
+import org.apache.avro.JsonProperties;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericData.StringType;
import org.apache.velocity.Template;
@@ -477,6 +478,23 @@ public String javaUnbox(Schema schema) {
}
}
+ /** Utility for template use. Returns the java annotations for a schema. */
+ public String[] javaAnnotations(JsonProperties props) {
+ JsonNode value = props.getJsonProp("javaAnnotation");
+ if (value == null)
+ return new String[0];
+ if (value.isTextual())
+ return new String[] { value.getTextValue() };
+ if (value.isArray()) {
+ int i = 0;
+ String[] result = new String[value.size()];
+ for (JsonNode v : value)
+ result[i++] = v.getTextValue();
+ return result;
+ }
+ return new String[0];
+ }
+
/** Utility for template use. Escapes quotes and backslashes. */
public static String javaEscape(Object o) {
return o.toString().replace("\\","\\\\").replace("\"", "\\\"");
View
3 ...mpiler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/enum.vm
@@ -22,6 +22,9 @@ package $schema.getNamespace();
#if ($schema.getDoc())
/** $schema.getDoc() */
#end
+#foreach ($annotation in $this.javaAnnotations($schema))
+@$annotation
+#end
public enum ${this.mangle($schema.getName())} {
#foreach ($symbol in ${schema.getEnumSymbols()})${this.mangle($symbol)}#if ($velocityHasNext), #end#end
;
View
3 ...piler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/fixed.vm
@@ -22,6 +22,9 @@ package $schema.getNamespace();
#if ($schema.getDoc())
/** $schema.getDoc() */
#end
+#foreach ($annotation in $this.javaAnnotations($schema))
+@$annotation
+#end
@org.apache.avro.specific.FixedSize($schema.getFixedSize())
public class ${this.mangle($schema.getName())} extends org.apache.avro.specific.SpecificFixed {
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}");
View
6 ...er/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/protocol.vm
@@ -23,6 +23,9 @@ package $protocol.getNamespace();
#if ($protocol.getDoc())
/** $protocol.getDoc() */
#end
+#foreach ($annotation in $this.javaAnnotations($protocol))
+@$annotation
+#end
public interface $this.mangle($protocol.getName()) {
public static final org.apache.avro.Protocol PROTOCOL = org.apache.avro.Protocol.parse("${this.javaEscape($protocol.toString())}");
#foreach ($e in $protocol.getMessages().entrySet())
@@ -32,6 +35,9 @@ public interface $this.mangle($protocol.getName()) {
#if ($message.getDoc())
/** $this.escapeForJavadoc($message.getDoc()) */
#end
+#foreach ($annotation in $this.javaAnnotations($message))
+ @$annotation
+#end
#if ($message.isOneWay())void#else${this.javaUnbox($response)}#end
${this.mangle($name)}(##
#foreach ($p in $message.getRequest().getFields())##
View
6 ...iler/src/main/velocity/org/apache/avro/compiler/specific/templates/java/classic/record.vm
@@ -22,12 +22,18 @@ package $schema.getNamespace();
#if ($schema.getDoc())
/** $schema.getDoc() */
#end
+#foreach ($annotation in $this.javaAnnotations($schema))
+@$annotation
+#end
public class ${this.mangle($schema.getName())}#if ($schema.isError()) extends org.apache.avro.specific.SpecificExceptionBase#else extends org.apache.avro.specific.SpecificRecordBase#end implements org.apache.avro.specific.SpecificRecord {
public static final org.apache.avro.Schema SCHEMA$ = new org.apache.avro.Schema.Parser().parse("${this.javaEscape($schema.toString())}");
#foreach ($field in $schema.getFields())
#if ($field.doc())
/** $field.doc() */
#end
+#foreach ($annotation in $this.javaAnnotations($field))
+ @$annotation
+#end
@Deprecated public ${this.javaUnbox($field.schema())} ${this.mangle($field.name(), $schema.isError())};
#end
#if ($schema.isError())
View
28 lang/java/ipc/src/test/java/org/apache/avro/TestAnnotation.java
@@ -0,0 +1,28 @@
+/**
+ * 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TestAnnotation {
+}
View
26 lang/java/ipc/src/test/java/org/apache/avro/compiler/specific/TestSpecificCompiler.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.FileWriter;
@@ -41,6 +42,13 @@
import org.apache.avro.Schema.Type;
import org.apache.avro.TestProtocolParsing;
import org.apache.avro.TestSchema;
+import org.apache.avro.TestAnnotation;
+
+import org.apache.avro.test.Simple;
+import org.apache.avro.test.TestRecord;
+import org.apache.avro.test.MD5;
+import org.apache.avro.test.Kind;
+
import org.apache.avro.compiler.specific.SpecificCompiler.OutputFile;
import org.junit.Test;
@@ -628,6 +636,24 @@ public void generateClearMethod() {
createRecord("test", false, schema, Schema$), Schema$));
}
+ @Test public void testAnnotations() throws Exception {
+ // an interface generated for protocol
+ assertNotNull(Simple.class.getAnnotation(TestAnnotation.class));
+ // a class generated for a record
+ assertNotNull(TestRecord.class.getAnnotation(TestAnnotation.class));
+ // a class generated for a fixed
+ assertNotNull(MD5.class.getAnnotation(TestAnnotation.class));
+ // a class generated for an enum
+ assertNotNull(Kind.class.getAnnotation(TestAnnotation.class));
+
+ // a field
+ assertNotNull(TestRecord.class.getField("name")
+ .getAnnotation(TestAnnotation.class));
+ // a method
+ assertNotNull(Simple.class.getMethod("ack")
+ .getAnnotation(TestAnnotation.class));
+ }
+
/**
* Checks that a schema passes through the SpecificCompiler, and,
* optionally, uses the system's Java compiler to check
View
6 lang/java/mapred/pom.xml
@@ -104,6 +104,12 @@
<artifactId>avro-ipc</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>avro-ipc</artifactId>
+ <classifier>tests</classifier>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
View
15 share/test/schemas/simple.avpr
@@ -2,15 +2,21 @@
"protocol": "Simple",
"doc": "Protocol used for testing.",
"version" : "1.6.2",
+ "javaAnnotation": ["javax.annotation.Generated(\"avro\")",
+ "org.apache.avro.TestAnnotation"],
"types": [
- {"name": "Kind", "type": "enum", "symbols": ["FOO","BAR","BAZ"]},
+ {"name": "Kind", "type": "enum", "symbols": ["FOO","BAR","BAZ"],
+ "javaAnnotation": "org.apache.avro.TestAnnotation"},
- {"name": "MD5", "type": "fixed", "size": 16},
+ {"name": "MD5", "type": "fixed", "size": 16,
+ "javaAnnotation": "org.apache.avro.TestAnnotation"},
{"name": "TestRecord", "type": "record",
+ "javaAnnotation": "org.apache.avro.TestAnnotation",
"fields": [
- {"name": "name", "type": "string", "order": "ignore"},
+ {"name": "name", "type": "string", "order": "ignore",
+ "javaAnnotation": "org.apache.avro.TestAnnotation"},
{"name": "kind", "type": "Kind", "order": "descending"},
{"name": "hash", "type": "MD5"}
]
@@ -66,7 +72,8 @@
"doc": "Send a one way message",
"request": [],
"response": "null",
- "one-way": true
+ "one-way": true,
+ "javaAnnotation": "org.apache.avro.TestAnnotation"
}
}

0 comments on commit 9b9068a

Please sign in to comment.