Skip to content

Commit

Permalink
Merge r996649 from trunk to 1.4 branch. Fixes: AVRO-634.
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/avro/branches/branch-1.4@996652 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
cutting committed Sep 13, 2010
1 parent 2e71d78 commit c7a3656
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 45 deletions.
2 changes: 2 additions & 0 deletions CHANGES.txt
Expand Up @@ -7,6 +7,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-657. Fix build so that md5 and sha1 checksum files contain
Expand Down
12 changes: 11 additions & 1 deletion doc/src/content/xdocs/idl.xml
Expand Up @@ -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">
Expand All @@ -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
Expand All @@ -380,7 +390,7 @@ protocol Simple {

MD5 hash;

union { MD5, null} nullableHash;
union { MD5, null} @aliases(["hash"]) nullableHash;

array&lt;long&gt; arrayOfLongs;
}
Expand Down
19 changes: 16 additions & 3 deletions lang/java/src/java/org/apache/avro/Schema.java
Expand Up @@ -30,6 +30,7 @@
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;
Expand Down Expand Up @@ -400,6 +401,11 @@ public Field(String name, Schema schema, String doc,
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;
Expand Down Expand Up @@ -476,11 +482,11 @@ public NamedSchema(Type type, Name name, String doc) {
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);
Expand Down Expand Up @@ -625,6 +631,13 @@ void fieldsToJson(Names names, JsonGenerator gen) throws IOException {
}
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();
}
Expand Down Expand Up @@ -1052,7 +1065,7 @@ private static Set<String> parseAliases(JsonNode node) {
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);
Expand Down
107 changes: 69 additions & 38 deletions lang/java/src/java/org/apache/avro/idl/idl.jj
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -1188,7 +1220,7 @@ void SchemaProperty(Map<String, String> properties):
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?
Expand All @@ -1199,17 +1231,16 @@ 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));
}
}

void VariableDeclarator(Schema type, List<Field> fields):
{
String name;
JsonNode defaultValue = null;
Map<String, String> props = new HashMap<String, String>();
Map<String, JsonNode> props = new LinkedHashMap<String, JsonNode>();
}
{
( SchemaProperty(props) )*
Expand All @@ -1220,13 +1251,18 @@ void VariableDeclarator(Schema type, List<Field> fields):

{
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);
}
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
}
Expand Down
3 changes: 2 additions & 1 deletion lang/java/src/test/idl/input/simple.avdl
Expand Up @@ -21,6 +21,7 @@
*/
@namespace("org.apache.avro.test")
protocol Simple {
@aliases(["org.foo.KindOf"])
enum Kind {
FOO,
BAR, // the bar enum value
Expand All @@ -36,7 +37,7 @@ protocol Simple {

@foo("bar") MD5 hash;

union { MD5, null} nullableHash;
union { MD5, null} @aliases(["hash", "hsh"]) nullableHash;
}

error TestError {
Expand Down
6 changes: 4 additions & 2 deletions lang/java/src/test/idl/output/simple.avpr
Expand Up @@ -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",
Expand All @@ -27,7 +28,8 @@
"type" : "MD5"
}, {
"name" : "nullableHash",
"type" : [ "MD5", "null" ]
"type" : [ "MD5", "null" ],
"aliases" : [ "hash", "hsh" ]
} ]
}, {
"type" : "error",
Expand Down

0 comments on commit c7a3656

Please sign in to comment.