Author: cutting
Date: Wed Aug 7 23:16:58 2013
New Revision: 1511531
URL: http://svn.apache.org/r1511531
Log:
AVRO-1341. Java: Add reflection annotations @AvroName, @AvroIgnore, @AvroMeta,
@AvroAlias and @AvroEncode. Contributed by Vincenz Priesnitz.
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java
(with props)
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java
(with props)
Modified:
avro/trunk/CHANGES.txt
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/Schema.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/reflect/FieldAccessReflect.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessUnsafe.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessor.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumWriter.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/Stringable.java
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/package.html
avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
Modified: avro/trunk/CHANGES.txt
URL:
http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Wed Aug 7 23:16:58 2013
@@ -19,6 +19,9 @@ Trunk (not yet released)
AVRO-1337. Java: Add a command line tool to generate schema files
from a protocol. (Bertrand Dechoux via cutting)
+ AVRO-1341. Java: Add reflection annotations @AvroName, @AvroIgnore,
+ @AvroMeta, @AvroAlias and @AvroEncode. (Vincenz Priesnitz via cutting)
+
IMPROVEMENTS
AVRO-1260. Ruby: Improve read performance. (Martin Kleppmann via cutting)
Modified: avro/trunk/lang/java/avro/src/main/java/org/apache/avro/Schema.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/Schema.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/main/java/org/apache/avro/Schema.java
(original)
+++ avro/trunk/lang/java/avro/src/main/java/org/apache/avro/Schema.java Wed Aug
7 23:16:58 2013
@@ -242,6 +242,11 @@ public abstract class Schema extends Jso
throw new AvroRuntimeException("Not a named type: "+this);
}
+ /** If this is a record, enum or fixed, add an alias. */
+ public void addAlias(String alias, String space) {
+ throw new AvroRuntimeException("Not a named type: "+this);
+ }
+
/** If this is a record, enum or fixed, return its aliases, if any. */
public Set<String> getAliases() {
throw new AvroRuntimeException("Not a named type: "+this);
@@ -481,9 +486,14 @@ public abstract class Schema extends Jso
public String getNamespace() { return name.space; }
public String getFullName() { return name.full; }
public void addAlias(String alias) {
+ addAlias(alias, null);
+ }
+ public void addAlias(String name, String space) {
if (aliases == null)
this.aliases = new LinkedHashSet<Name>();
- aliases.add(new Name(alias, name.space));
+ if (space == null)
+ space = this.name.space;
+ aliases.add(new Name(name, space));
}
public Set<String> getAliases() {
Set<String> result = new LinkedHashSet<String>();
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=1511531&r1=1511530&r2=1511531&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
Wed Aug 7 23:16:58 2013
@@ -400,7 +400,7 @@ public class GenericDatumReader<D> imple
new HashMap<Class,Constructor>();
@SuppressWarnings("unchecked")
- private Object newInstanceFromString(Class c, String s) {
+ protected Object newInstanceFromString(Class c, String s) {
try {
Constructor ctor = stringCtorCache.get(c);
if (ctor == null) {
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,37 @@
+/**
+ * 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Adds the given name and space as an alias to the schema.
+ * Avro files of this schema can be read into classes
+ * named by the alias.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface AvroAlias {
+ String NULL = "NOT A VALID NAMESPACE";
+
+ String alias();
+ String space() default NULL;
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroAlias.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,35 @@
+/**
+ * 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Expert: Fields with this annotation are encoded using the given custom
encoder.
+ * This annotation overrides {@link org.apache.avro.reflect.Stringable
Stringable} and {@link org.apache.avro.reflect.Nullable Nullable}.
+ * Since no validation is performed, invalid custom encodings may result in an
unreadable file.
+ * Use of {@link org.apache.avro.io.ValidatingEncoder} is recommended.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface AvroEncode {
+ Class<? extends CustomEncoding<?>> using();
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroEncode.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java
Wed Aug 7 23:16:58 2013
@@ -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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Marks a field as transient.
+ * Such a field will not get written into or read from a schema,
+ * when using reflection.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface AvroIgnore {
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroIgnore.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,34 @@
+/**
+ * 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Adds the given key:Value pair as metadata into the schema,
+ * at the corresponding node.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.FIELD})
+public @interface AvroMeta {
+ String key();
+ String value();
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroMeta.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,34 @@
+/**
+ * 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Sets the avroname for this java field.
+ * When reading into this class, a reflectdatumreader
+ * looks for a schema field with the avroname.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface AvroName {
+ String value();
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/AvroName.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,53 @@
+/**
+ * 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.io.IOException;
+
+import org.apache.avro.Schema;
+import org.apache.avro.io.Decoder;
+import org.apache.avro.io.Encoder;
+
+/**
+ * Expert: a custom encoder and decoder that writes
+ * an object directly to avro.
+ * No validation is performed to check that the encoding conforms to the
schema.
+ * Invalid implementations may result in an unreadable file.
+ * The use of {@link org.apache.avro.io.ValidatingEncoder} is recommended.
+ *
+ * @param <T> The class of objects that can be serialized with this encoder /
decoder.
+ */
+public abstract class CustomEncoding<T> {
+
+ protected Schema schema;
+
+
+ protected abstract void write(Object datum, Encoder out) throws IOException;
+
+ protected abstract T read(Object reuse, Decoder in) throws IOException;
+
+ T read(Decoder in) throws IOException {
+ return this.read(null, in);
+ }
+
+ protected Schema getSchema() {
+ return schema;
+ }
+
+
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/CustomEncoding.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java?rev=1511531&view=auto
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java
(added)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java
Wed Aug 7 23:16:58 2013
@@ -0,0 +1,53 @@
+/**
+ * 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.io.IOException;
+import java.util.Date;
+
+import org.apache.avro.Schema;
+import org.apache.avro.io.Decoder;
+import org.apache.avro.io.Encoder;
+
+/**
+ * This encoder/decoder writes a java.util.Date object as a long to
+ * avro and reads a Date object from long.
+ * The long stores the number of milliseconds since January 1, 1970, 00:00:00
GMT
+ * represented by the Date object.
+ */
+public class DateAsLongEncoding extends CustomEncoding<Date> {
+ {
+ schema = Schema.create(Schema.Type.LONG);
+ schema.addProp("CustomEncoding", "DateAsLongEncoding");
+ }
+
+ @Override
+ protected final void write(Object datum, Encoder out) throws IOException {
+ out.writeLong(((Date)datum).getTime());
+ }
+
+ @Override
+ protected final Date read(Object reuse, Decoder in) throws IOException {
+ if (reuse != null && reuse instanceof Date) {
+ ((Date)reuse).setTime(in.readLong());
+ return (Date)reuse;
+ }
+ else return new Date(in.readLong());
+ }
+
+}
Propchange:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/DateAsLongEncoding.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessReflect.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessReflect.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessReflect.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessReflect.java
Wed Aug 7 23:16:58 2013
@@ -29,10 +29,14 @@ class FieldAccessReflect extends FieldAc
private final class ReflectionBasedAccessor extends FieldAccessor {
private final Field field;
+ private boolean isStringable;
+ private boolean isCustomEncoded;
public ReflectionBasedAccessor(Field field) {
this.field = field;
this.field.setAccessible(true);
+ isStringable = field.isAnnotationPresent(Stringable.class);
+ isCustomEncoded = field.isAnnotationPresent(AvroEncode.class);
}
@Override
@@ -50,6 +54,21 @@ class FieldAccessReflect extends FieldAc
IOException {
field.set(object, value);
}
+
+ @Override
+ protected Field getField() {
+ return field;
+ }
+
+ @Override
+ protected boolean isStringable() {
+ return isStringable;
+ }
+
+ @Override
+ protected boolean isCustomEncoded() {
+ return isCustomEncoded;
+ }
}
}
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessUnsafe.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessUnsafe.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessUnsafe.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessUnsafe.java
Wed Aug 7 23:16:58 2013
@@ -20,6 +20,7 @@ package org.apache.avro.reflect;
import java.io.IOException;
import java.lang.reflect.Field;
+import org.apache.avro.AvroRuntimeException;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.Encoder;
@@ -43,6 +44,13 @@ class FieldAccessUnsafe extends FieldAcc
@Override
protected FieldAccessor getAccessor(Field field) {
+ AvroEncode enc = field.getAnnotation(AvroEncode.class);
+ if (enc != null)
+ try {
+ return new UnsafeCustomEncodedField(field, enc.using().newInstance() );
+ } catch (Exception e) {
+ throw new AvroRuntimeException("Could not instantiate custom
Encoding");
+ }
Class<?> c = field.getType();
if (c == int.class)
return new UnsafeIntField(field);
@@ -66,20 +74,34 @@ class FieldAccessUnsafe extends FieldAcc
abstract static class UnsafeCachedField extends FieldAccessor {
protected final long offset;
+ protected Field field;
+ protected final boolean isStringable;
- UnsafeCachedField(long offset) {
- this.offset = offset;
+ UnsafeCachedField(Field f) {
+ this.offset = UNSAFE.objectFieldOffset(f);
+ this.field = f;
+ this.isStringable = f.isAnnotationPresent(Stringable.class);
+ }
+
+ @Override
+ protected Field getField() {
+ return field;
}
@Override
protected boolean supportsIO() {
return true;
}
+
+ @Override
+ protected boolean isStringable() {
+ return isStringable;
+ }
}
final static class UnsafeIntField extends UnsafeCachedField {
UnsafeIntField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -105,7 +127,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeFloatField extends UnsafeCachedField {
protected UnsafeFloatField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -131,7 +153,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeShortField extends UnsafeCachedField {
protected UnsafeShortField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -157,7 +179,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeByteField extends UnsafeCachedField {
protected UnsafeByteField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -183,7 +205,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeBooleanField extends UnsafeCachedField {
protected UnsafeBooleanField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -209,7 +231,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeCharField extends UnsafeCachedField {
protected UnsafeCharField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -235,7 +257,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeLongField extends UnsafeCachedField {
protected UnsafeLongField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -261,7 +283,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeDoubleField extends UnsafeCachedField {
protected UnsafeDoubleField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -287,7 +309,7 @@ class FieldAccessUnsafe extends FieldAcc
final static class UnsafeObjectField extends UnsafeCachedField {
protected UnsafeObjectField(Field f) {
- super(UNSAFE.objectFieldOffset(f));
+ super(f);
}
@Override
@@ -306,4 +328,38 @@ class FieldAccessUnsafe extends FieldAcc
}
}
+
+ final static class UnsafeCustomEncodedField extends UnsafeCachedField {
+
+ private CustomEncoding<?> encoding;
+
+ UnsafeCustomEncodedField(Field f, CustomEncoding<?> encoding) {
+ super(f);
+ this.encoding = encoding;
+ }
+
+ @Override
+ protected Object get(Object object) throws IllegalAccessException {
+ return UNSAFE.getObject(object, offset);
+ }
+
+ @Override
+ protected void set(Object object, Object value) throws
IllegalAccessException, IOException {
+ UNSAFE.putObject(object, offset, value);
+ }
+
+ @Override
+ protected void read(Object object, Decoder in) throws IOException {
+ UNSAFE.putObject(object, offset, encoding.read(in));
+ }
+
+ @Override
+ protected void write(Object object, Encoder out) throws IOException {
+ encoding.write(UNSAFE.getObject(object, offset), out);
+ }
+
+ protected boolean isCustomEncoded() {
+ return true;
+ }
+ }
}
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessor.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessor.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessor.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/FieldAccessor.java
Wed Aug 7 23:16:58 2013
@@ -18,6 +18,7 @@
package org.apache.avro.reflect;
import java.io.IOException;
+import java.lang.reflect.Field;
import org.apache.avro.io.Decoder;
import org.apache.avro.io.Encoder;
@@ -40,4 +41,15 @@ abstract class FieldAccessor {
protected boolean supportsIO() {
return false;
}
+
+ protected abstract Field getField();
+
+ protected boolean isStringable() {
+ return false;
+ }
+
+ protected boolean isCustomEncoded() {
+ return false;
+ }
+
}
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
Wed Aug 7 23:16:58 2013
@@ -211,8 +211,14 @@ public class ReflectData extends Specifi
private ClassAccessorData(Class<?> c) {
clazz = c;
for(Field f : getFields(c, false)) {
+ if (f.isAnnotationPresent(AvroIgnore.class)) {
+ continue;
+ }
FieldAccessor accessor =
ReflectionUtil.getFieldAccess().getAccessor(f);
- byName.put(f.getName(), accessor);
+ AvroName avroname = f.getAnnotation(AvroName.class);
+ byName.put( (avroname != null
+ ? avroname.value()
+ : f.getName()) , accessor);
}
}
@@ -436,18 +442,22 @@ public class ReflectData extends Specifi
for (int i = 0; i < constants.length; i++)
symbols.add(constants[i].name());
schema = Schema.createEnum(name, null /* 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);
+ consumeAvroAliasAnnotation(c, schema);
} else if (IndexedRecord.class.isAssignableFrom(c)) { // specific
return super.createSchema(type, names);
} else { // record
List<Schema.Field> fields = new ArrayList<Schema.Field>();
boolean error = Throwable.class.isAssignableFrom(c);
schema = Schema.createRecord(name, null /* doc */, space, error);
+ consumeAvroAliasAnnotation(c, schema);
names.put(c.getName(), schema);
for (Field field : getCachedFields(c))
- if
((field.getModifiers()&(Modifier.TRANSIENT|Modifier.STATIC))==0){
+ if ((field.getModifiers()&(Modifier.TRANSIENT|Modifier.STATIC))==0
+ && !field.isAnnotationPresent(AvroIgnore.class)) {
Schema fieldSchema = createFieldSchema(field, names);
JsonNode defaultValue = null;
if (fieldSchema.getType() == Schema.Type.UNION) {
@@ -456,14 +466,29 @@ public class ReflectData extends Specifi
defaultValue = NullNode.getInstance();
}
}
- Schema.Field recordField = new Schema.Field(field.getName(),
- fieldSchema, null /* doc */, defaultValue);
+ AvroName annotatedName = field.getAnnotation(AvroName.class);
// Rename fields
+ String fieldName = (annotatedName != null)
+ ? annotatedName.value()
+ : field.getName();
+ Schema.Field recordField
+ = new Schema.Field(fieldName, fieldSchema, null, defaultValue);
+
+ AvroMeta meta = field.getAnnotation(AvroMeta.class);
// add metadata
+ if (meta != null)
+ recordField.addProp(meta.key(), meta.value());
+ for(Schema.Field f : fields) {
+ if (f.name().equals(fieldName))
+ throw new AvroTypeException("double field entry: "+
fieldName);
+ }
fields.add(recordField);
}
if (error) // add Throwable message
fields.add(new Schema.Field("detailMessage", THROWABLE_MESSAGE,
null, null));
schema.setFields(fields);
+ AvroMeta meta = c.getAnnotation(AvroMeta.class);
+ if (meta != null)
+ schema.addProp(meta.key(), meta.value());
}
names.put(fullName, schema);
}
@@ -536,7 +561,17 @@ public class ReflectData extends Specifi
/** Create a schema for a field. */
protected Schema createFieldSchema(Field field, Map<String, Schema> names) {
+ AvroEncode enc = field.getAnnotation(AvroEncode.class);
+ if (enc != null)
+ try {
+ return enc.using().newInstance().getSchema();
+ } catch (Exception e) {
+ throw new AvroRuntimeException("Could not create schema from custom
serializer for " + field.getName());
+ }
Schema schema = createSchema(field.getGenericType(), names);
+ if (field.isAnnotationPresent(Stringable.class)) { // Stringable
+ schema = Schema.create(Schema.Type.STRING);
+ }
if (field.isAnnotationPresent(Nullable.class)) // nullable
schema = makeNullable(schema);
return schema;
@@ -650,4 +685,15 @@ public class ReflectData extends Specifi
protected Object getRecordState(Object record, Schema schema) {
return getFieldAccessors(record.getClass(), schema);
}
+
+ private void consumeAvroAliasAnnotation(Class<?> c, Schema schema) {
+ AvroAlias alias = c.getAnnotation(AvroAlias.class);
+ if (alias != null) {
+ String space = alias.space();
+ if (AvroAlias.NULL.equals(space))
+ space = null;
+ schema.addAlias(alias.alias(), space);
+ }
+ }
+
}
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumReader.java
Wed Aug 7 23:16:58 2013
@@ -87,6 +87,9 @@ public class ReflectDatumReader<T> exten
}
if (elementClass == null) {
+ elementClass = collectionClass.getComponentType();
+ }
+ if (elementClass == null) {
ReflectData data = (ReflectData)getData();
elementClass = data.getClass(schema.getElementType());
}
@@ -204,10 +207,24 @@ public class ReflectDatumReader<T> exten
ResolvingDecoder in, Object state) throws IOException {
if (state != null) {
FieldAccessor accessor = ((FieldAccessor[]) state)[f.pos()];
- if (accessor != null && !Schema.Type.UNION.equals(f.schema().getType())
- && accessor.supportsIO()) {
- accessor.read(record, in);
- return;
+ if (accessor != null) {
+ if (accessor.supportsIO()
+ && (!Schema.Type.UNION.equals(f.schema().getType())
+ || accessor.isCustomEncoded())) {
+ accessor.read(record, in);
+ return;
+ }
+ if (accessor.isStringable()) {
+ try {
+ String asString = (String) read(null, f.schema(), in);
+ accessor.set(record, asString == null
+ ? null
+ : newInstanceFromString(accessor.getField().getType(),
asString));
+ return;
+ } catch (Exception e) {
+ throw new AvroRuntimeException("Failed to read Stringable", e);
+ }
+ }
}
}
super.readField(record, f, oldDatum, in, state);
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumWriter.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumWriter.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumWriter.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectDatumWriter.java
Wed Aug 7 23:16:58 2013
@@ -154,10 +154,22 @@ public class ReflectDatumWriter<T> exten
throws IOException {
if (state != null) {
FieldAccessor accessor = ((FieldAccessor[]) state)[f.pos()];
- if (accessor != null && !Schema.Type.UNION.equals(f.schema().getType())
- && accessor.supportsIO()) {
- accessor.write(record, out);
- return;
+ if (accessor != null) {
+ if (accessor.supportsIO()
+ && (!Schema.Type.UNION.equals(f.schema().getType())
+ || accessor.isCustomEncoded())) {
+ accessor.write(record, out);
+ return;
+ }
+ if (accessor.isStringable()) {
+ try {
+ Object object = accessor.get(record);
+ write(f.schema(), (object == null) ? null : object.toString(),
out);
+ } catch (IllegalAccessException e) {
+ throw new AvroRuntimeException("Failed to write Stringable", e);
+ }
+ return;
+ }
}
}
super.writeField(record, f, out, state);
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/Stringable.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/Stringable.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/Stringable.java
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/Stringable.java
Wed Aug 7 23:16:58 2013
@@ -24,11 +24,11 @@ import java.lang.annotation.RetentionPol
import java.lang.annotation.Target;
/**
- * Declares that a class should be represented by an Avro string. It's {@link
+ * Declares that a class or field should be represented by an Avro string.
It's {@link
* Object#toString()} method will be used to convert it to a string, and its
* single String parameter constructor will be used to create instances.
*/
@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
+@Target({ElementType.TYPE, ElementType.FIELD})
@Documented
public @interface Stringable {}
Modified:
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/package.html
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/package.html?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/package.html
(original)
+++
avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/package.html
Wed Aug 7 23:16:58 2013
@@ -77,5 +77,22 @@ and other uses of polymorphism.
will cause a type to be serialized via its {@link java.lang.Object#toString()
toString} method.
+<p>Fields annotated with {@link org.apache.avro.reflect.AvroIgnore AvroIgnore}
+will not be written or read to.
+
+<p> The {@link org.apache.avro.reflect.Avroname AvroName} annotation renames
+the field in the schema to the given name. The reflect datum reader will look
+for a schema field with the given name, when trying to read into such an
+annotated java field.
+
+<p>The {@link org.apache.avro.reflect.AvroMeta AvroMeta} annotation adds an
+arbitrary key:value pair in the schema at the node of the java field.
+
+<p>The {@link org.apache.avro.reflect.AvroEncode AvroEncode} annotation forces
+the use of an custom encoder. This annotation overrides
+{@link org.apache.avro.reflect.Stringable Stringable} and
+{@link org.apache.avro.reflect.Nullable Nullable}.
+
+
</body>
</html>
Modified:
avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
URL:
http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java?rev=1511531&r1=1511530&r2=1511531&view=diff
==============================================================================
---
avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
(original)
+++
avro/trunk/lang/java/avro/src/test/java/org/apache/avro/reflect/TestReflect.java
Wed Aug 7 23:16:58 2013
@@ -433,6 +433,45 @@ public class TestReflect {
+"{\"name\":\"a\",\"type\":\"int\"},"
+"{\"name\":\"b\",\"type\":\"long\"}]}");
}
+
+ public static class RAvroIgnore { @AvroIgnore int a; }
+ @Test public void testAnnotationAvroIgnore() throws Exception {
+ check(RAvroIgnore.class,
"{\"type\":\"record\",\"name\":\"RAvroIgnore\",\"namespace\":"
+ +"\"org.apache.avro.reflect.TestReflect$\",\"fields\":[]}");
+ }
+
+ public static class RAvroMeta { @AvroMeta(key="K", value="V") int a; }
+ @Test public void testAnnotationAvroMeta() throws Exception {
+ check(RAvroMeta.class,
"{\"type\":\"record\",\"name\":\"RAvroMeta\",\"namespace\":"
+ +"\"org.apache.avro.reflect.TestReflect$\",\"fields\":["
+ +"{\"name\":\"a\",\"type\":\"int\",\"K\":\"V\"}]}");
+ }
+
+ public static class RAvroName { @AvroName("b") int a; }
+ @Test public void testAnnotationAvroName() throws Exception {
+ check(RAvroName.class,
"{\"type\":\"record\",\"name\":\"RAvroName\",\"namespace\":"
+ +"\"org.apache.avro.reflect.TestReflect$\",\"fields\":["
+ +"{\"name\":\"b\",\"type\":\"int\"}]}");
+ }
+
+ public static class RAvroNameCollide { @AvroName("b") int a; int b; }
+ @Test(expected=Exception.class)
+ public void testAnnotationAvroNameCollide() throws Exception {
+ check(RAvroNameCollide.class,
"{\"type\":\"record\",\"name\":\"RAvroNameCollide\",\"namespace\":"
+ +"\"org.apache.avro.reflect.TestReflect$\",\"fields\":["
+ +"{\"name\":\"b\",\"type\":\"int\"},"
+ +"{\"name\":\"b\",\"type\":\"int\"}]}");
+ }
+
+ public static class RAvroStringableField { @Stringable int a; }
+ public void testAnnotationAvroStringableFields() throws Exception {
+ check(RAvroStringableField.class,
"{\"type\":\"record\",\"name\":\"RAvroNameCollide\",\"namespace\":"
+ +"\"org.apache.avro.reflect.TestReflect$\",\"fields\":["
+ +"{\"name\":\"a\",\"type\":\"String\"}]}");
+ }
+
+
+
private void check(Object o, String schemaJson) {
check(o.getClass(), schemaJson);
@@ -460,6 +499,129 @@ public class TestReflect {
assertEquals(record, decoded);
}
+ public static class AvroEncRecord {
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date date;
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof AvroEncRecord)) return false;
+ return date.equals(((AvroEncRecord)o).date);
+ }
+ }
+
+ public static class multipleAnnotationRecord {
+ @AvroIgnore
+ @Stringable
+ Integer i1;
+
+ @AvroIgnore
+ @Nullable
+ Integer i2;
+
+ @AvroIgnore
+ @AvroName("j")
+ Integer i3;
+
+ @AvroIgnore
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date i4;
+
+ @Stringable
+ @Nullable
+ Integer i5;
+
+ @Stringable
+ @AvroName("j6")
+ Integer i6 = 6;
+
+ @Stringable
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date i7 = new java.util.Date(7L);
+
+ @Nullable
+ @AvroName("j8")
+ Integer i8;
+
+ @Nullable
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date i9;
+
+ @AvroName("j10")
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date i10 = new java.util.Date(10L);
+
+ @Stringable
+ @Nullable
+ @AvroName("j11")
+ @AvroEncode(using=DateAsLongEncoding.class)
+ java.util.Date i11;
+ }
+
+ @Test
+ public void testMultipleAnnotations() throws IOException {
+ Schema schm = ReflectData.get().getSchema(multipleAnnotationRecord.class);
+ ReflectDatumWriter<multipleAnnotationRecord> writer =
+ new ReflectDatumWriter<multipleAnnotationRecord>(schm);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ multipleAnnotationRecord record = new multipleAnnotationRecord();
+ record.i1 = 1;
+ record.i2 = 2;
+ record.i3 = 3;
+ record.i4 = new java.util.Date(4L);
+ record.i5 = 5;
+ record.i6 = 6;
+ record.i7 = new java.util.Date(7L);
+ record.i8 = 8;
+ record.i9 = new java.util.Date(9L);
+ record.i10 = new java.util.Date(10L);
+ record.i11 = new java.util.Date(11L);
+
+ writer.write(record, factory.directBinaryEncoder(out, null));
+ ReflectDatumReader<multipleAnnotationRecord> reader =
+ new ReflectDatumReader<multipleAnnotationRecord>(schm);
+ multipleAnnotationRecord decoded =
+ reader.read(new multipleAnnotationRecord(),
DecoderFactory.get().binaryDecoder(
+ out.toByteArray(), null));
+ assertTrue(decoded.i1 == null);
+ assertTrue(decoded.i2 == null);
+ assertTrue(decoded.i3 == null);
+ assertTrue(decoded.i4 == null);
+ assertTrue(decoded.i5 == 5);
+ assertTrue(decoded.i6 == 6);
+ assertTrue(decoded.i7.getTime() == 7);
+ assertTrue(decoded.i8 == 8);
+ assertTrue(decoded.i9.getTime() == 9);
+ assertTrue(decoded.i10.getTime() == 10);
+ assertTrue(decoded.i11.getTime() == 11);
+ }
+
+
+ @Test
+ public void testAvroEncodeInducing() throws IOException {
+ Schema schm = ReflectData.get().getSchema(AvroEncRecord.class);
+ assertEquals(schm.toString(),
"{\"type\":\"record\",\"name\":\"AvroEncRecord\",\"namespace" +
+
"\":\"org.apache.avro.reflect.TestReflect$\",\"fields\":[{\"name\":\"date\"," +
+
"\"type\":{\"type\":\"long\",\"CustomEncoding\":\"DateAsLongEncoding\"}}]}");
+ }
+
+ @Test
+ public void testAvroEncodeIO() throws IOException {
+ Schema schm = ReflectData.get().getSchema(AvroEncRecord.class);
+ ReflectDatumWriter<AvroEncRecord> writer =
+ new ReflectDatumWriter<AvroEncRecord>(schm);
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ AvroEncRecord record = new AvroEncRecord();
+ record.date = new java.util.Date(948833323L);
+ writer.write(record, factory.directBinaryEncoder(out, null));
+ ReflectDatumReader<AvroEncRecord> reader =
+ new ReflectDatumReader<AvroEncRecord>(schm);
+ AvroEncRecord decoded =
+ reader.read(new AvroEncRecord(), DecoderFactory.get().binaryDecoder(
+ out.toByteArray(), null));
+ assertEquals(record, decoded);
+ }
+
@Test
public void testRecordWithNullIO() throws IOException {
ReflectData reflectData = ReflectData.AllowNull.get();
@@ -768,4 +930,17 @@ public class TestReflect {
}
}
+ @AvroAlias(alias="a", space="b")
+ private static class AliasA { }
+ @AvroAlias(alias="a", space="")
+ private static class AliasB { }
+ @AvroAlias(alias="a")
+ private static class AliasC { }
+
+ @Test
+ public void testAvroAlias() {
+ check(AliasA.class,
"{\"type\":\"record\",\"name\":\"AliasA\",\"namespace\":\"org.apache.avro.reflect.TestReflect$\",\"fields\":[],\"aliases\":[\"b.a\"]}");
+ check(AliasB.class,
"{\"type\":\"record\",\"name\":\"AliasB\",\"namespace\":\"org.apache.avro.reflect.TestReflect$\",\"fields\":[],\"aliases\":[\"a\"]}");
+ check(AliasC.class,
"{\"type\":\"record\",\"name\":\"AliasC\",\"namespace\":\"org.apache.avro.reflect.TestReflect$\",\"fields\":[],\"aliases\":[\"a\"]}");
+ }
}