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/09/13 21:21:11 UTC

svn commit: r996649 - in /avro/trunk: CHANGES.txt doc/src/content/xdocs/idl.xml lang/java/src/java/org/apache/avro/Schema.java lang/java/src/java/org/apache/avro/idl/idl.jj lang/java/src/test/idl/input/simple.avdl lang/java/src/test/idl/output/simple.avpr

Author: cutting
Date: Mon Sep 13 19:21:10 2010
New Revision: 996649

URL: http://svn.apache.org/viewvc?rev=996649&view=rev
Log:
AVRO-634.  IDL: Add support for aliases.

Modified:
    avro/trunk/CHANGES.txt
    avro/trunk/doc/src/content/xdocs/idl.xml
    avro/trunk/lang/java/src/java/org/apache/avro/Schema.java
    avro/trunk/lang/java/src/java/org/apache/avro/idl/idl.jj
    avro/trunk/lang/java/src/test/idl/input/simple.avdl
    avro/trunk/lang/java/src/test/idl/output/simple.avpr

Modified: avro/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/avro/trunk/CHANGES.txt?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/CHANGES.txt (original)
+++ avro/trunk/CHANGES.txt Mon Sep 13 19:21:10 2010
@@ -11,6 +11,8 @@ Avro 1.4.1 (unreleased)
     AVRO-655. Change build so that 'dist' target no longer also runs C
     and C++ unit tests. (cutting)
 
+    AVRO-634. IDL: Add support for aliases. (cutting)
+
   BUG FIXES
 
     AVRO-666. Remove an extraneous pdb.set_trace() that crept into schema.py

Modified: avro/trunk/doc/src/content/xdocs/idl.xml
URL: http://svn.apache.org/viewvc/avro/trunk/doc/src/content/xdocs/idl.xml?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/doc/src/content/xdocs/idl.xml (original)
+++ avro/trunk/doc/src/content/xdocs/idl.xml Mon Sep 13 19:21:10 2010
@@ -352,6 +352,14 @@ protocol MyProto {
           defined in <code>someOtherNamespace</code> and <code>Bar</code> will be defined in <code>firstNamespace</code>
           as it inherits its default from its container.
         </p>
+	<p>Type and field aliases are specified with
+	the <code>@aliases</code> annotation as follows:</p>
+        <source>
+@aliases(["org.old.OldRecord", "org.ancient.AncientRecord"])
+record MyRecord {
+  string @aliases(["oldField", "ancientField"]) myNewField;
+}
+        </source>
       </section>
     </section>
     <section id="example">
@@ -363,6 +371,8 @@ protocol MyProto {
  */
 @namespace("org.apache.avro.test")
 protocol Simple {
+
+  @aliases(["org.foo.KindOf"])
   enum Kind {
     FOO,
     BAR, // the bar enum value
@@ -380,7 +390,7 @@ protocol Simple {
 
     MD5 hash;
 
-    union { MD5, null} nullableHash;
+    union { MD5, null} @aliases(["hash"]) nullableHash;
 
     array&lt;long&gt; arrayOfLongs;
   }

Modified: avro/trunk/lang/java/src/java/org/apache/avro/Schema.java
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/src/java/org/apache/avro/Schema.java?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/lang/java/src/java/org/apache/avro/Schema.java (original)
+++ avro/trunk/lang/java/src/java/org/apache/avro/Schema.java Mon Sep 13 19:21:10 2010
@@ -30,6 +30,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -400,6 +401,11 @@ public abstract class Schema {
     public synchronized void addProp(String name, String value) {
       props.add(name, value);
     }
+    public void addAlias(String alias) {
+      if (aliases == null)
+        this.aliases = new LinkedHashSet<String>();
+      aliases.add(alias);
+    }
     public boolean equals(Object other) {
       if (other == this) return true;
       if (!(other instanceof Field)) return false;
@@ -476,11 +482,11 @@ public abstract class Schema {
     public String getFullName() { return name.full; }
     public void addAlias(String alias) {
       if (aliases == null)
-        this.aliases = new HashSet<Name>();
+        this.aliases = new LinkedHashSet<Name>();
       aliases.add(new Name(alias, name.space));
     }
     public Set<String> getAliases() {
-      Set<String> result = new HashSet<String>();
+      Set<String> result = new LinkedHashSet<String>();
       if (aliases != null)
         for (Name alias : aliases)
           result.add(alias.full);
@@ -625,6 +631,13 @@ public abstract class Schema {
         }
         if (f.order() != Field.Order.ASCENDING)
           gen.writeStringField("order", f.order().name);
+        if (f.aliases != null) {
+          gen.writeFieldName("aliases");
+          gen.writeStartArray();
+          for (String alias : f.aliases)
+            gen.writeString(alias);
+          gen.writeEndArray();
+        }
         f.props.write(gen);
         gen.writeEndObject();
       }
@@ -1052,7 +1065,7 @@ public abstract class Schema {
       return null;
     if (!aliasesNode.isArray())
       throw new SchemaParseException("aliases not an array: "+node);
-    Set<String> aliases = new HashSet<String>();
+    Set<String> aliases = new LinkedHashSet<String>();
     for (JsonNode aliasNode : aliasesNode) {
       if (!aliasNode.isTextual())
         throw new SchemaParseException("alias not a string: "+aliasNode);

Modified: avro/trunk/lang/java/src/java/org/apache/avro/idl/idl.jj
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/src/java/org/apache/avro/idl/idl.jj?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/lang/java/src/java/org/apache/avro/idl/idl.jj (original)
+++ avro/trunk/lang/java/src/java/org/apache/avro/idl/idl.jj Mon Sep 13 19:21:10 2010
@@ -96,6 +96,33 @@ public class Idl
     this.inputDir = inputFile.getParentFile();
   }
 
+  private ParseException error(String message, Token token) {
+    return new ParseException
+      (message+", at line "+token.beginLine+", column "+token.beginColumn);
+  }
+
+  private String getTextProp(String key, Map<String,JsonNode> props,
+                             Token token) throws ParseException {
+    JsonNode value = props.get(key);
+    if (value.isTextual())
+      return value.getTextValue();
+    throw error(key+" property must be textual: "+value, token);
+  }
+
+  private List<String> getTextProps(String key, Map<String,JsonNode> props,
+                             Token token) throws ParseException {
+    JsonNode value = props.get(key);
+    if (!value.isArray())
+      throw error(key+" property must be array: "+value, token);
+    List<String> values = new ArrayList<String>();
+    for (JsonNode n : value)
+      if (n.isTextual())
+        values.add(n.getTextValue());
+      else
+        throw error(key+" values must be textual: "+n, token);
+    return values;
+  }
+
 }
 
 PARSER_END(Idl)
@@ -941,15 +968,14 @@ Protocol CompilationUnit():
 Schema NamedSchemaDeclaration():
 {
   Schema s;
-  Map<String, String> props = new HashMap<String, String>();
+  Map<String, JsonNode> props = new LinkedHashMap<String, JsonNode>();
   String savedSpace = this.namespace;
 }
 {
   ( SchemaProperty(props) )*
   {
-    if (props.containsKey("namespace")) {
-      this.namespace = props.get("namespace");
-    }
+    if (props.containsKey("namespace"))
+      this.namespace = getTextProp("namespace", props, token);
   }
  (
      s = FixedDeclaration()
@@ -958,6 +984,16 @@ Schema NamedSchemaDeclaration():
  )
  {
    this.namespace = savedSpace;
+
+   for (String key : props.keySet())
+     if ("namespace".equals(key)) {               // already handled: ignore
+     } else if ("aliases".equals(key)) {          // aliases
+       for (String alias : getTextProps("aliases", props, token))
+         s.addAlias(alias);
+     } else if (props.get(key).isTextual()) {     // ignore other non-textual
+       s.addProp(key, getTextProp(key, props, token));
+     }
+
    return s;
  }
 }
@@ -991,14 +1027,13 @@ Protocol ProtocolDeclaration():
 {
   String name;
   Protocol p;
-  Map<String, String> props = new HashMap<String, String>();
+  Map<String, JsonNode> props = new LinkedHashMap<String, JsonNode>();
 }
 {
   ( SchemaProperty(props) )*
   {
-    if (props.containsKey("namespace")) {
-      namespace = props.get("namespace");
-    }
+    if (props.containsKey("namespace"))
+      namespace = getTextProp("namespace", props, token);
   }
  "protocol"
    name = Identifier()
@@ -1091,7 +1126,7 @@ Protocol ImportIdl() : {
       try {
         return new Idl(new File(inputDir, importFile)).CompilationUnit();
       } catch (IOException e) {
-        throw new ParseException("Error importing "+importFile+": "+e);
+        throw error("Error importing "+importFile+": "+e, token);
       }        
     }
 }
@@ -1106,7 +1141,7 @@ Protocol ImportProtocol() : {
       try {
         return Protocol.parse(new File(inputDir, importFile));
       } catch (IOException e) {
-        throw new ParseException("Error importing "+importFile+": "+e);
+        throw error("Error importing "+importFile+": "+e, token);
       }        
     }
 }
@@ -1120,7 +1155,7 @@ Schema ImportSchema() : {
       try {
         return Schema.parse(new File(inputDir, importFile));
       } catch (IOException e) {
-        throw new ParseException("Error importing "+importFile+": "+e);
+        throw error("Error importing "+importFile+": "+e, token);
       }        
     }
 }
@@ -1167,19 +1202,16 @@ Schema RecordDeclaration():
   }
 }
 
-void SchemaProperty(Map<String, String> properties):
+void SchemaProperty(Map<String, JsonNode> properties):
 {
   String key;
-  String val;
+  JsonNode val;
 }
 {
-  "@" key = Identifier() "(" val = JsonString() ")"
+  "@" key = Identifier() "(" val = Json() ")"
   {
-    if (properties.containsKey(key)) {
-      throw new ParseException("Property '" + key + "' already specified " +
-                               " at line " + token.beginLine + ", column " +
-                               token.beginColumn);
-    }
+    if (properties.containsKey(key))
+      throw error("Property '" + key + "' already specified", token);
     properties.put(key, val);
   }
 }
@@ -1188,7 +1220,7 @@ void SchemaProperty(Map<String, String> 
 void FieldDeclaration(List<Field> fields):
 {
   Schema type;
-  Map<String, String> props = new HashMap<String, String>();
+  Map<String, JsonNode> props = new LinkedHashMap<String, JsonNode>();
 }
 {
   // TODO should we be able to specify properties on any Type?
@@ -1199,9 +1231,8 @@ void FieldDeclaration(List<Field> fields
   VariableDeclarator(type, fields) ( "," VariableDeclarator(type, fields) )*
   ";"
   {
-    for (Map.Entry<String, String> propEntry : props.entrySet()) {
-      type.addProp(propEntry.getKey(), propEntry.getValue());
-    }
+    for (String key : props.keySet())
+      type.addProp(key, getTextProp(key, props, token));
   }
 }
 
@@ -1209,7 +1240,7 @@ void VariableDeclarator(Schema type, Lis
 {
   String name;
   JsonNode defaultValue = null;
-  Map<String, String> props = new HashMap<String, String>();
+  Map<String, JsonNode> props = new LinkedHashMap<String, JsonNode>();
 }
 {
     ( SchemaProperty(props) )*
@@ -1220,13 +1251,18 @@ void VariableDeclarator(Schema type, Lis
     
   {
     Field.Order order = Field.Order.ASCENDING;
-    for (Map.Entry<String, String> prop : props.entrySet())
-      if ("order".equals(prop.getKey()))
-        order = Field.Order.valueOf(prop.getValue().toUpperCase());
+    for (String key : props.keySet())
+      if ("order".equals(key))
+        order = Field.Order.valueOf(getTextProp(key,props,token).toUpperCase());
     Field field = new Field(name, type, null, defaultValue, order);
-    for (Map.Entry<String, String> prop : props.entrySet())
-      if (!"order".equals(prop.getKey()))
-        field.addProp(prop.getKey(), prop.getValue());
+    for (String key : props.keySet())
+      if ("order".equals(key)) {                  // already handled: ignore
+      } else if ("aliases".equals(key)) {         // aliases
+        for (String alias : getTextProps("aliases", props, token))
+          field.addAlias(alias);
+      } else if (props.get(key).isTextual()) {    // ignore other non-textual
+        field.addProp(key, getTextProp(key, props, token));
+      }
     fields.add(field);
   }
 }
@@ -1250,9 +1286,7 @@ Message MessageDeclaration(Protocol p):
   {
     Schema errors = Schema.createUnion(errorSchemata);
     if (oneWay && response.getType() != Type.NULL)
-      throw new ParseException("One-way message'" + name + "' must return void"
-                               + " at line " + token.beginLine + ", column " +
-                               token.beginColumn);
+      throw error("One-way message'"+name+"' must return void", token);
     return oneWay
     ? p.createMessage(name, null, request)
     : p.createMessage(name, null, request, response, errors);
@@ -1349,11 +1383,8 @@ Schema ReferenceType():
     if ((name.indexOf('.') == -1) && namespace != null)
       name = namespace + "." + name;
     Schema type = names.get(name);
-    if (type == null) {
-      throw new ParseException("Undefined name '" + name + "'" +
-                               " at line " + token.beginLine + ", column " +
-                               token.beginColumn);
-    }
+    if (type == null)
+      throw error("Undefined name '" + name + "'", token);
     return type;
   }
 }

Modified: avro/trunk/lang/java/src/test/idl/input/simple.avdl
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/src/test/idl/input/simple.avdl?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/lang/java/src/test/idl/input/simple.avdl (original)
+++ avro/trunk/lang/java/src/test/idl/input/simple.avdl Mon Sep 13 19:21:10 2010
@@ -21,6 +21,7 @@
  */
 @namespace("org.apache.avro.test")
 protocol Simple {
+  @aliases(["org.foo.KindOf"])
   enum Kind {
     FOO,
     BAR, // the bar enum value
@@ -36,7 +37,7 @@ protocol Simple {
 
     @foo("bar") MD5 hash;
 
-    union { MD5, null} nullableHash;
+    union { MD5, null} @aliases(["hash", "hsh"]) nullableHash;
   }
 
   error TestError {

Modified: avro/trunk/lang/java/src/test/idl/output/simple.avpr
URL: http://svn.apache.org/viewvc/avro/trunk/lang/java/src/test/idl/output/simple.avpr?rev=996649&r1=996648&r2=996649&view=diff
==============================================================================
--- avro/trunk/lang/java/src/test/idl/output/simple.avpr (original)
+++ avro/trunk/lang/java/src/test/idl/output/simple.avpr Mon Sep 13 19:21:10 2010
@@ -4,7 +4,8 @@
   "types" : [ {
     "type" : "enum",
     "name" : "Kind",
-    "symbols" : [ "FOO", "BAR", "BAZ" ]
+    "symbols" : [ "FOO", "BAR", "BAZ" ],
+    "aliases" : [ "org.foo.KindOf" ]
   }, {
     "type" : "fixed",
     "name" : "MD5",
@@ -27,7 +28,8 @@
       "type" : "MD5"
     }, {
       "name" : "nullableHash",
-      "type" : [ "MD5", "null" ]
+      "type" : [ "MD5", "null" ],
+      "aliases" : [ "hash", "hsh" ]
     } ]
   }, {
     "type" : "error",