You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@avro.apache.org by dk...@apache.org on 2018/11/20 20:28:38 UTC
[avro] branch master updated: AVRO-1658: Java: Add reflection
annotation @AvroDoc.
This is an automated email from the ASF dual-hosted git repository.
dkulp pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/master by this push:
new 01a347e AVRO-1658: Java: Add reflection annotation @AvroDoc.
01a347e is described below
commit 01a347e996a20406b0bf13026dd375725c4efb7f
Author: Evan McClain <ae...@gmail.com>
AuthorDate: Sun Sep 17 00:13:54 2017 -0400
AVRO-1658: Java: Add reflection annotation @AvroDoc.
@AvroMeta can be used for other keys, but doc is passed into the field's
constructor.
Patch 2: @AvroDoc should work for class-level documentation too.
Closes #189
---
.../main/java/org/apache/avro/reflect/AvroDoc.java | 17 ++++++++++++
.../java/org/apache/avro/reflect/ReflectData.java | 12 ++++++---
.../java/org/apache/avro/reflect/TestReflect.java | 30 ++++++++++++++++++++++
3 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroDoc.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroDoc.java
new file mode 100644
index 0000000..7b46a47
--- /dev/null
+++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroDoc.java
@@ -0,0 +1,17 @@
+package org.apache.avro.reflect;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Sets the avrodoc for this java field.
+ * When reading into this class, a reflectdatumreader
+ * looks for a schema field with the avrodoc.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.FIELD})
+public @interface AvroDoc {
+ String value();
+}
diff --git a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
index 12d3e15..3e9e079 100644
--- a/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
+++ b/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
@@ -574,6 +574,8 @@ public class ReflectData extends SpecificData {
String fullName = c.getName();
Schema schema = names.get(fullName);
if (schema == null) {
+ AvroDoc annotatedDoc = c.getAnnotation(AvroDoc.class); // Docstring
+ String doc = (annotatedDoc != null) ? annotatedDoc.value() : null;
String name = c.getSimpleName();
String space = c.getPackage() == null ? "" : c.getPackage().getName();
if (c.getEnclosingClass() != null) // nested class
@@ -590,18 +592,18 @@ public class ReflectData extends SpecificData {
Enum[] constants = (Enum[])c.getEnumConstants();
for (int i = 0; i < constants.length; i++)
symbols.add(constants[i].name());
- schema = Schema.createEnum(name, null /* doc */, space, symbols);
+ schema = Schema.createEnum(name, doc, space, symbols);
consumeAvroAliasAnnotation(c, schema);
} else if (GenericFixed.class.isAssignableFrom(c)) { // fixed
int size = c.getAnnotation(FixedSize.class).value();
- schema = Schema.createFixed(name, null /* doc */, space, size);
+ schema = Schema.createFixed(name, doc, space, size);
consumeAvroAliasAnnotation(c, schema);
} else if (IndexedRecord.class.isAssignableFrom(c)) { // specific
return super.createSchema(type, names);
} else { // record
List<Schema.Field> fields = new ArrayList<>();
boolean error = Throwable.class.isAssignableFrom(c);
- schema = Schema.createRecord(name, null /* doc */, space, error);
+ schema = Schema.createRecord(name, doc, space, error);
consumeAvroAliasAnnotation(c, schema);
names.put(c.getName(), schema);
for (Field field : getCachedFields(c))
@@ -613,6 +615,8 @@ public class ReflectData extends SpecificData {
Object defaultValue = (defaultAnnotation == null)
? null
: Schema.parseJsonToObject(defaultAnnotation.value());
+ annotatedDoc = field.getAnnotation(AvroDoc.class); // Docstring
+ doc = (annotatedDoc != null) ? annotatedDoc.value() : null;
if (defaultValue == null
&& fieldSchema.getType() == Schema.Type.UNION) {
@@ -626,7 +630,7 @@ public class ReflectData extends SpecificData {
? annotatedName.value()
: field.getName();
Schema.Field recordField
- = new Schema.Field(fieldName, fieldSchema, null, defaultValue);
+ = new Schema.Field(fieldName, fieldSchema, doc, defaultValue);
AvroMeta meta = field.getAnnotation(AvroMeta.class); // add metadata
if (meta != null)
diff --git a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
index 45ee2af..c58030d 100644
--- a/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
+++ b/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
@@ -1128,4 +1128,34 @@ public class TestReflect {
public void testNullableByteArrayNullValue() throws Exception {
checkReadWrite(new NullableBytesTest());
}
+
+ private enum DocTestEnum {
+ ENUM_1,
+ ENUM_2
+ }
+
+ @AvroDoc("DocTest class docs")
+ private static class DocTest {
+ @AvroDoc("Some Documentation")
+ int foo;
+
+ @AvroDoc("Some other Documentation")
+ DocTestEnum enums;
+
+ @AvroDoc("And again")
+ DefaultTest defaultTest;
+ }
+
+ @Test
+ public void testAvroDoc() {
+ check(DocTest.class,
+ "{\"type\":\"record\",\"name\":\"DocTest\",\"namespace\":\"org.apache.avro.reflect.TestReflect\","
+ + "\"doc\":\"DocTest class docs\","
+ + "\"fields\":[{\"name\":\"foo\",\"type\":\"int\",\"doc\":\"Some Documentation\"},"
+ + "{\"name\":\"enums\",\"type\":{\"type\":\"enum\",\"name\":\"DocTestEnum\","
+ + "\"symbols\":[\"ENUM_1\",\"ENUM_2\"]},\"doc\":\"Some other Documentation\"},"
+ + "{\"name\":\"defaultTest\",\"type\":{\"type\":\"record\",\"name\":\"DefaultTest\","
+ + "\"fields\":[{\"name\":\"foo\",\"type\":\"int\",\"default\":1}]},\"doc\":\"And again\"}]}");
+ }
+
}