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 2012/09/10 20:31:49 UTC

svn commit: r1383026 - in /avro/trunk: CHANGES.txt lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java lang/java/avro/src/test/java/org/apache/avro/TestReflect.java

Author: cutting
Date: Mon Sep 10 18:31:48 2012
New Revision: 1383026

URL: http://svn.apache.org/viewvc?rev=1383026&view=rev
Log:
AVRO-1146. Java: Serialize several built-in Java classes as strings, including BigDecimal, BigInteger, URI, URL, Date and File.  Contributed by Alexandre Normand and cutting.

Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/lang/java/avro/src/main/java/org/apache/avro/reflect/ReflectData.java
    avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=1383026&r1=1383025&r2=1383026&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Mon Sep 10 18:31:48 2012
@@ -6,6 +6,10 @@ Avro 1.7.2 (unreleased)
 
   IMPROVEMENTS
 
+    AVRO-1146. Java: Serialize several built-in Java classes as
+    strings, including BigDecimal, BigInteger, URI, URL, Date and
+    File.  (Alexandre Normand and cutting)
+
   BUG FIXES
 
     AVRO-1128. Java: Fix SpecificRecordBase#equals() to work for

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=1383026&r1=1383025&r2=1383026&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 Mon Sep 10 18:31:48 2012
@@ -33,6 +33,8 @@ import java.util.Collections;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
+import java.util.HashSet;
 
 import org.apache.avro.AvroRemoteException;
 import org.apache.avro.AvroRuntimeException;
@@ -74,7 +76,22 @@ public class ReflectData extends Specifi
   
   private static final ReflectData INSTANCE = new ReflectData();
 
-  protected ReflectData() {}
+  /** Read/write some common builtin classes as strings.  Representing these as
+   * strings isn't always best, as they aren't always ordered ideally, but at
+   * least they're stored.  Also note that, for compatibility, only classes
+   * that wouldn't be otherwise correctly readable or writable should be added
+   * here, e.g., those without a no-arg constructor or those whose fields are
+   * all transient. */
+  private Set<Class> stringableClasses = new HashSet<Class>(); {
+    stringableClasses.add(java.math.BigDecimal.class);
+    stringableClasses.add(java.math.BigInteger.class);
+    stringableClasses.add(java.net.URI.class);
+    stringableClasses.add(java.net.URL.class);
+    stringableClasses.add(java.io.File.class);
+    stringableClasses.add(java.util.Date.class);
+  }
+
+  public ReflectData() {}
   
   /** Construct with a particular classloader. */
   public ReflectData(ClassLoader classLoader) {
@@ -84,6 +101,13 @@ public class ReflectData extends Specifi
   /** Return the singleton instance. */
   public static ReflectData get() { return INSTANCE; }
 
+  /** Cause a class to be treated as though it had an {@link Stringable}
+   ** annotation. */
+  public ReflectData addStringable(Class c) {
+    stringableClasses.add(c);
+    return this;
+  }
+
   @Override
   public DatumReader createDatumReader(Schema schema) {
     return new ReflectDatumReader(schema, schema, this);
@@ -215,7 +239,11 @@ public class ReflectData extends Specifi
       if (collectionClass != null)
         return collectionClass;
       return java.lang.reflect.Array.newInstance(getClass(schema.getElementType()),0).getClass();
-    case STRING:  return String.class;
+    case STRING:
+      Class stringClass = getClassProp(schema, CLASS_PROP);
+      if (stringClass != null)
+        return stringClass;
+      return String.class;
     case BYTES:   return BYTES_CLASS;
     case INT:
       String intClass = schema.getProp(CLASS_PROP);
@@ -263,8 +291,12 @@ public class ReflectData extends Specifi
       return result;
     } else if (type instanceof Class) {                      // Class
       Class<?> c = (Class<?>)type;
-      if (c.isPrimitive() || Number.class.isAssignableFrom(c)
-          || c == Void.class || c == Boolean.class)          // primitive
+      if (c.isPrimitive() ||                                 // primitives
+          c == Void.class || c == Boolean.class || 
+          c == Integer.class || c == Long.class ||
+          c == Float.class || c == Double.class || 
+          c == Byte.class || c == Short.class || 
+          c == Character.class)
         return super.createSchema(type, names);
       if (c.isArray()) {                                     // array
         Class component = c.getComponentType();
@@ -294,7 +326,8 @@ public class ReflectData extends Specifi
         Union union = c.getAnnotation(Union.class);
         if (union != null) {                                 // union annotated
           return getAnnotatedUnion(union, names);
-        } else if (c.isAnnotationPresent(Stringable.class)){ // Stringable
+        } else if (c.isAnnotationPresent(Stringable.class) || // Stringable
+                   stringableClasses.contains(c)) {
           Schema result = Schema.create(Schema.Type.STRING);
           result.addProp(CLASS_PROP, c.getName());
           return result;

Modified: avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java?rev=1383026&r1=1383025&r2=1383026&view=diff
==============================================================================
--- avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java (original)
+++ avro/trunk/lang/java/avro/src/test/java/org/apache/avro/TestReflect.java Mon Sep 10 18:31:48 2012
@@ -603,6 +603,25 @@ public class TestReflect {
     checkBinary(schema, null);
   }
 
+  /** Test stringable classes. */
+  @Test public void testStringables() throws Exception {
+    checkStringable(java.math.BigDecimal.class, "10");
+    checkStringable(java.math.BigInteger.class, "20");
+    checkStringable(java.net.URI.class, "foo://bar:9000/baz");
+    checkStringable(java.net.URL.class, "http://bar:9000/baz");
+    checkStringable(java.io.File.class, "foo.bar");
+    checkStringable(java.util.Date.class, "Sat, 12 Aug 1995 13:30:00 GMT");
+  }
+
+  public void checkStringable(Class c, String value) throws Exception {
+    ReflectData data = new ReflectData().get();
+    Schema schema = data.getSchema(c);
+    assertEquals
+      ("{\"type\":\"string\",\"java-class\":\""+c.getName()+"\"}",
+       schema.toString());
+    checkBinary(schema, c.getConstructor(String.class).newInstance(value));
+  }
+
   public static void checkBinary(Schema schema, Object datum)
     throws IOException {
     ReflectDatumWriter<Object> writer = new ReflectDatumWriter<Object>(schema);