[add] AVRO-1723 and AVRO-1667 Project: http://git-wip-us.apache.org/repos/asf/avro/repo Commit: http://git-wip-us.apache.org/repos/asf/avro/commit/1f6fa7b7 Tree: http://git-wip-us.apache.org/repos/asf/avro/tree/1f6fa7b7 Diff: http://git-wip-us.apache.org/repos/asf/avro/diff/1f6fa7b7
Branch: refs/heads/master Commit: 1f6fa7b79efde2eb999de34334b686a77b23e46a Parents: 273106b Author: Zoltan Farkas <[email protected]> Authored: Wed Nov 18 17:44:50 2015 -0500 Committer: Zoltan Farkas <[email protected]> Committed: Wed Dec 9 17:25:56 2015 -0500 ---------------------------------------------------------------------- .../java/org/apache/avro/io/parsing/Symbol.java | 97 ++++---- .../avro/compiler/idl/SchemaResolver.java | 229 +++++++++++++++++++ .../javacc/org/apache/avro/compiler/idl/idl.jj | 7 +- .../java/compiler/src/test/idl/input/cycle.avdl | 24 ++ .../compiler/src/test/idl/output/cycle.avpr | 55 +++++ .../org/apache/avro/compiler/idl/TestCycle.java | 105 +++++++++ lang/java/ipc/nb-configuration.xml | 18 ++ 7 files changed, 489 insertions(+), 46 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/avro/src/main/java/org/apache/avro/io/parsing/Symbol.java ---------------------------------------------------------------------- diff --git a/lang/java/avro/src/main/java/org/apache/avro/io/parsing/Symbol.java b/lang/java/avro/src/main/java/org/apache/avro/io/parsing/Symbol.java index 08a9d14..9d73381 100644 --- a/lang/java/avro/src/main/java/org/apache/avro/io/parsing/Symbol.java +++ b/lang/java/avro/src/main/java/org/apache/avro/io/parsing/Symbol.java @@ -60,7 +60,7 @@ public abstract class Symbol { * the symbols that forms the production for this symbol. The * sequence is in the reverse order of production. This is useful * for easy copying onto parsing stack. - * + * * Please note that this is a final. So the production for a symbol * should be known before that symbol is constructed. This requirement * cannot be met for those symbols which are recursive (e.g. a record that @@ -77,8 +77,8 @@ public abstract class Symbol { protected Symbol(Kind kind) { this(kind, null); } - - + + protected Symbol(Kind kind, Symbol[] production) { this.production = production; this.kind = kind; @@ -120,7 +120,7 @@ public abstract class Symbol { static Symbol error(String e) { return new ErrorAction(e); } - + /** * A convenience method to construct a ResolvingAction. * @param w The writer symbol @@ -129,32 +129,32 @@ public abstract class Symbol { static Symbol resolve(Symbol w, Symbol r) { return new ResolvingAction(w, r); } - + private static class Fixup { - public final Symbol[] symbols; - public final int pos; - + public Symbol[] symbols; + public int pos; + public Fixup(Symbol[] symbols, int pos) { this.symbols = symbols; this.pos = pos; } } - + public Symbol flatten(Map<Sequence, Sequence> map, Map<Sequence, List<Fixup>> map2) { return this; } - + public int flattenedSize() { return 1; } - + /** * Flattens the given sub-array of symbols into an sub-array of symbols. Every * <tt>Sequence</tt> in the input are replaced by its production recursively. * Non-<tt>Sequence</tt> symbols, they internally have other symbols * those internal symbols also get flattened. - * + * * The algorithm does a few tricks to handle recursive symbol definitions. * In order to avoid infinite recursion with recursive symbols, we have a map * of Symbol->Symbol. Before fully constructing a flattened symbol for a @@ -168,7 +168,7 @@ public abstract class Symbol { * has not not be fully constructed yet, we copy a bunch of <tt>null</tt>s. * Fix-up remembers all those <tt>null</tt> patches. The fix-ups gets finally * filled when we know the symbols to occupy those patches. - * + * * @param in The array of input symbols to flatten * @param start The position where the input sub-array starts. * @param out The output that receives the flattened list of symbols. The @@ -190,6 +190,15 @@ public abstract class Symbol { List<Fixup> l = map2.get(s); if (l == null) { System.arraycopy(p, 0, out, j, p.length); + // Fixups need to be relocated! + for (List<Fixup> value : map2.values()) { + for (Fixup fixup : value) { + if (fixup.symbols == p) { + fixup.symbols = out; + fixup.pos += j; + } + } + } } else { l.add(new Fixup(out, j)); } @@ -232,7 +241,7 @@ public abstract class Symbol { public static class ImplicitAction extends Symbol { /** - * Set to <tt>true</tt> if and only if this implicit action is + * Set to <tt>true</tt> if and only if this implicit action is * a trailing action. That is, it is an action that follows * real symbol. E.g {@link Symbol#DEFAULT_END_ACTION}. */ @@ -241,13 +250,13 @@ public abstract class Symbol { private ImplicitAction() { this(false); } - + private ImplicitAction(boolean isTrailing) { super(Kind.IMPLICIT_ACTION); this.isTrailing = isTrailing; } } - + protected static class Root extends Symbol { private Root(Symbol... symbols) { super(Kind.ROOT, makeProduction(symbols)); @@ -262,7 +271,7 @@ public abstract class Symbol { return result; } } - + protected static class Sequence extends Symbol implements Iterable<Symbol> { private Sequence(Symbol[] productions) { super(Kind.SEQUENCE, productions); @@ -271,19 +280,19 @@ public abstract class Symbol { public Symbol get(int index) { return production[index]; } - + public int size() { return production.length; } - + public Iterator<Symbol> iterator() { return new Iterator<Symbol>() { private int pos = production.length; - + public boolean hasNext() { return 0 < pos; } - + public Symbol next() { if (0 < pos) { return production[--pos]; @@ -291,7 +300,7 @@ public abstract class Symbol { throw new NoSuchElementException(); } } - + public void remove() { throw new UnsupportedOperationException(); } @@ -306,7 +315,7 @@ public abstract class Symbol { map.put(this, result); List<Fixup> l = new ArrayList<Fixup>(); map2.put(result, l); - + flatten(production, 0, result.production, 0, map, map2); for (Fixup f : l) { @@ -326,19 +335,19 @@ public abstract class Symbol { public static class Repeater extends Symbol { public final Symbol end; - + private Repeater(Symbol end, Symbol... sequenceToRepeat) { super(Kind.REPEATER, makeProduction(sequenceToRepeat)); this.end = end; production[0] = this; } - + private static Symbol[] makeProduction(Symbol[] p) { Symbol[] result = new Symbol[p.length + 1]; System.arraycopy(p, 0, result, 1, p.length); return result; } - + @Override public Repeater flatten(Map<Sequence, Sequence> map, Map<Sequence, List<Fixup>> map2) { @@ -349,9 +358,9 @@ public abstract class Symbol { } } - + /** - * Returns true if the Parser contains any Error symbol, indicating that it may fail + * Returns true if the Parser contains any Error symbol, indicating that it may fail * for some inputs. */ public static boolean hasErrors(Symbol symbol) { @@ -374,7 +383,7 @@ public abstract class Symbol { throw new RuntimeException("unknown symbol kind: " + symbol.kind); } } - + private static boolean hasErrors(Symbol root, Symbol[] symbols) { if(null != symbols) { for(Symbol s: symbols) { @@ -388,7 +397,7 @@ public abstract class Symbol { } return false; } - + public static class Alternative extends Symbol { public final Symbol[] symbols; public final String[] labels; @@ -397,15 +406,15 @@ public abstract class Symbol { this.symbols = symbols; this.labels = labels; } - + public Symbol getSymbol(int index) { return symbols[index]; } - + public String getLabel(int index) { return labels[index]; } - + public int size() { return symbols.length; } @@ -454,7 +463,7 @@ public abstract class Symbol { public static EnumAdjustAction enumAdjustAction(int rsymCount, Object[] adj) { return new EnumAdjustAction(rsymCount, adj); } - + public static class EnumAdjustAction extends IntCheckAction { public final Object[] adjustments; @Deprecated public EnumAdjustAction(int rsymCount, Object[] adjustments) { @@ -478,7 +487,7 @@ public abstract class Symbol { this.writer = writer; this.reader = reader; } - + @Override public ResolvingAction flatten(Map<Sequence, Sequence> map, Map<Sequence, List<Fixup>> map2) { @@ -487,7 +496,7 @@ public abstract class Symbol { } } - + public static SkipAction skipAction(Symbol symToSkip) { return new SkipAction(symToSkip); } @@ -498,7 +507,7 @@ public abstract class Symbol { super(true); this.symToSkip = symToSkip; } - + @Override public SkipAction flatten(Map<Sequence, Sequence> map, Map<Sequence, List<Fixup>> map2) { @@ -510,7 +519,7 @@ public abstract class Symbol { public static FieldAdjustAction fieldAdjustAction(int rindex, String fname) { return new FieldAdjustAction(rindex, fname); } - + public static class FieldAdjustAction extends ImplicitAction { public final int rindex; public final String fname; @@ -519,7 +528,7 @@ public abstract class Symbol { this.fname = fname; } } - + public static FieldOrderAction fieldOrderAction(Schema.Field[] fields) { return new FieldOrderAction(fields); } @@ -553,13 +562,13 @@ public abstract class Symbol { this.rindex = rindex; this.symToParse = symToParse; } - + @Override public UnionAdjustAction flatten(Map<Sequence, Sequence> map, Map<Sequence, List<Fixup>> map2) { return new UnionAdjustAction(rindex, symToParse.flatten(map, map2)); } - + } /** For JSON. */ @@ -573,11 +582,11 @@ public abstract class Symbol { super(symbols.size()); this.symbols = symbols; } - + public String getLabel(int n) { return symbols.get(n); } - + public int findLabel(String l) { if (l != null) { for (int i = 0; i < symbols.size(); i++) { @@ -619,7 +628,7 @@ public abstract class Symbol { public static final Symbol RECORD_END = new ImplicitAction(true); public static final Symbol UNION_END = new ImplicitAction(true); public static final Symbol FIELD_END = new ImplicitAction(true); - + public static final Symbol DEFAULT_END_ACTION = new ImplicitAction(true); public static final Symbol MAP_KEY_MARKER = new Symbol.Terminal("map-key-marker"); http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/compiler/src/main/java/org/apache/avro/compiler/idl/SchemaResolver.java ---------------------------------------------------------------------- diff --git a/lang/java/compiler/src/main/java/org/apache/avro/compiler/idl/SchemaResolver.java b/lang/java/compiler/src/main/java/org/apache/avro/compiler/idl/SchemaResolver.java new file mode 100644 index 0000000..df0c7ac --- /dev/null +++ b/lang/java/compiler/src/main/java/org/apache/avro/compiler/idl/SchemaResolver.java @@ -0,0 +1,229 @@ +/* + * Copyright 2015 The Apache Software Foundation. + * + * Licensed 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.compiler.idl; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.avro.JsonProperties; +import org.apache.avro.LogicalType; +import org.apache.avro.Protocol; +import org.apache.avro.Schema; +import org.codehaus.jackson.JsonNode; + +/** + * + * @author zoly + */ +final class SchemaResolver { + + private SchemaResolver() { } + + private static final String UR_SCHEMA_ATTR = "org.apache.avro.compiler.idl.unresolved.name"; + + static Schema unresolvedSchema(final String name) { + Schema schema = Schema.createRecord("UnresolvedSchema", "unresolved schema", + "org.apache.avro.compiler", false, Collections.EMPTY_LIST); + schema.addProp(UR_SCHEMA_ATTR, name); + return schema; + } + + static boolean isUnresolvedSchema(final Schema schema) { + return (schema.getType() == Schema.Type.RECORD && schema.getProp(UR_SCHEMA_ATTR) != null); + } + + static String getUnresolvedSchemaName(final Schema schema) { + String name = schema.getProp(UR_SCHEMA_ATTR); + if (name == null) { + throw new IllegalArgumentException("Schema " + schema + " is not a unresolved schema"); + } else { + return name; + } + } + + + + static Protocol resolve(final Protocol protocol) { + Protocol result = new Protocol(protocol.getName(), protocol.getDoc(), protocol.getNamespace()); + final Collection<Schema> types = protocol.getTypes(); + List<Schema> newSchemas = new ArrayList(types.size()); + Map<String, Schema> processed = new HashMap<String, Schema>(); + for (Schema schema : types) { + newSchemas.add(resolve(schema, protocol, processed)); + } + result.setTypes(newSchemas); + + for (Map.Entry<String, Protocol.Message> entry : protocol.getMessages().entrySet()) { + Protocol.Message value = entry.getValue(); + Protocol.Message nvalue; + if (value.isOneWay()) { + Schema request = value.getRequest(); + nvalue = result.createMessage(value.getName(), value.getDoc(), + value.getObjectProps(), intern(request, processed)); + } else { + Schema request = value.getRequest(); + Schema response = value.getResponse(); + Schema errors = value.getErrors(); + nvalue = result.createMessage(value.getName(), value.getDoc(), + value.getObjectProps(), intern(request, processed), + intern(response, processed), intern(errors, processed)); + } + result.getMessages().put(entry.getKey(), nvalue); + } + copyProps(protocol, result); + return result; + } + + private static void copyProps(final JsonProperties from, final JsonProperties to) { + for (Map.Entry<String, JsonNode> entry : from.getJsonProps().entrySet()) { + to.addProp(entry.getKey(), entry.getValue()); + } + } + + + static Schema resolve(final Schema schema, final Protocol protocol, final Map<String, Schema> processed) { + final String fullName = schema.getFullName(); + if (fullName != null && processed.containsKey(fullName)) { + return processed.get(schema.getFullName()); + } else if (isUnresolvedSchema(schema)) { + final String unresolvedSchemaName = getUnresolvedSchemaName(schema); + Schema type = protocol.getType(unresolvedSchemaName); + if (type == null) { + throw new IllegalArgumentException("Cannot resolve " + unresolvedSchemaName); + } + return resolve(type, protocol, processed); + } else { + switch (schema.getType()) { + case RECORD: + Schema createRecord = Schema.createRecord(schema.getName(), schema.getDoc(), schema.getNamespace(), + schema.isError()); + processed.put(schema.getFullName(), createRecord); + final List<Schema.Field> currFields = schema.getFields(); + List<Schema.Field> newFields = new ArrayList<Schema.Field>(currFields.size()); + for (Schema.Field field : currFields) { + Schema.Field nf = new Schema.Field(field.name(), resolve(field.schema(), protocol, processed), + field.doc(), field.defaultVal(), field.order()); + for (String alias : field.aliases()) { + nf.addAlias(alias); + } + newFields.add(nf); + } + createRecord.setFields(newFields); + final LogicalType lt = schema.getLogicalType(); + if (lt != null) { + lt.addToSchema(createRecord); + } + copyProps(schema, createRecord); + return createRecord; + case MAP: + Schema result = Schema.createMap(resolve(schema.getValueType(), protocol, processed)); + copyProps(schema, result); + return result; + case ARRAY: + Schema aresult = Schema.createArray(resolve(schema.getElementType(), protocol, processed)); + copyProps(schema, aresult); + return aresult; + case UNION: + final List<Schema> uTypes = schema.getTypes(); + List<Schema> newTypes = new ArrayList<Schema>(uTypes.size()); + for (Schema s : uTypes) { + newTypes.add(resolve(s, protocol, processed)); + } + Schema bresult = Schema.createUnion(newTypes); + copyProps(schema, bresult); + return bresult; + case ENUM: + case FIXED: + case STRING: + case BYTES: + case INT: + case LONG: + case FLOAT: + case DOUBLE: + case BOOLEAN: + case NULL: + return schema; + default: + throw new RuntimeException("Unknown type: " + schema); + } + } + } + + public static Schema intern(final Schema schema, final Map<String, Schema> processed) { + if (schema == null) { + return null; + } + final String fullName = schema.getFullName(); + if (fullName != null && processed.containsKey(fullName)) { + return processed.get(schema.getFullName()); + } else { + switch (schema.getType()) { + case RECORD: + Schema createRecord = Schema.createRecord(schema.getName(), schema.getDoc(), schema.getNamespace(), + schema.isError()); + processed.put(schema.getFullName(), createRecord); + final List<Schema.Field> currFields = schema.getFields(); + List<Schema.Field> newFields = new ArrayList<Schema.Field>(currFields.size()); + for (Schema.Field field : currFields) { + Schema.Field nf = new Schema.Field(field.name(), intern(field.schema(), processed), + field.doc(), field.defaultVal(), field.order()); + for (String alias : field.aliases()) { + nf.addAlias(alias); + } + newFields.add(nf); + } + createRecord.setFields(newFields); + final LogicalType lt = schema.getLogicalType(); + if (lt != null) { + lt.addToSchema(createRecord); + } + copyProps(schema, createRecord); + return createRecord; + case MAP: + return Schema.createMap(intern(schema.getValueType(), processed)); + case ARRAY: + return Schema.createArray(intern(schema.getElementType(), processed)); + case UNION: + final List<Schema> uTypes = schema.getTypes(); + List<Schema> newTypes = new ArrayList<Schema>(uTypes.size()); + for (Schema s : uTypes) { + newTypes.add(intern(s, processed)); + } + return Schema.createUnion(newTypes); + case ENUM: + case FIXED: + case STRING: + case BYTES: + case INT: + case LONG: + case FLOAT: + case DOUBLE: + case BOOLEAN: + case NULL: + return schema; + default: + throw new RuntimeException("Unknown type: " + schema); + } + } + } + + + + +} http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj ---------------------------------------------------------------------- diff --git a/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj b/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj index 8f60b83..a8f0623 100644 --- a/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj +++ b/lang/java/compiler/src/main/javacc/org/apache/avro/compiler/idl/idl.jj @@ -999,7 +999,7 @@ Protocol CompilationUnit(): ( < "\u001a" > )? ( <STUFF_TO_IGNORE: ~[]> )? <EOF> - { return p; } + { return SchemaResolver.resolve(p); } } /* @@ -1465,7 +1465,10 @@ Schema ReferenceType(): name = namespace + "." + name; Schema type = names.get(name); if (type == null) - throw error("Undefined name '" + name + "'", token); + //throw error("Undefined name '" + name + "'", token); + { + type = SchemaResolver.unresolvedSchema(name); + } return type; } } http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/compiler/src/test/idl/input/cycle.avdl ---------------------------------------------------------------------- diff --git a/lang/java/compiler/src/test/idl/input/cycle.avdl b/lang/java/compiler/src/test/idl/input/cycle.avdl new file mode 100644 index 0000000..f434431 --- /dev/null +++ b/lang/java/compiler/src/test/idl/input/cycle.avdl @@ -0,0 +1,24 @@ +@namespace("org.apache.avro.gen") +protocol Cycle { + + record SampleNode { + int count = 0; + array<SamplePair> subNodes; + } + + record Method { + string declaringClass; + string methodName; + } + + record SamplePair { + Method method; + SampleNode node; + } + + record SelfRef { + string something; + array<SelfRef> subNodes = []; + } + +} http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/compiler/src/test/idl/output/cycle.avpr ---------------------------------------------------------------------- diff --git a/lang/java/compiler/src/test/idl/output/cycle.avpr b/lang/java/compiler/src/test/idl/output/cycle.avpr new file mode 100644 index 0000000..53658af --- /dev/null +++ b/lang/java/compiler/src/test/idl/output/cycle.avpr @@ -0,0 +1,55 @@ +{ + "protocol" : "Cycle", + "namespace" : "org.apache.avro.gen", + "types" : [ { + "type" : "record", + "name" : "SampleNode", + "fields" : [ { + "name" : "count", + "type" : "int", + "default" : 0 + }, { + "name" : "subNodes", + "type" : { + "type" : "array", + "items" : { + "type" : "record", + "name" : "SamplePair", + "fields" : [ { + "name" : "method", + "type" : { + "type" : "record", + "name" : "Method", + "fields" : [ { + "name" : "declaringClass", + "type" : "string" + }, { + "name" : "methodName", + "type" : "string" + } ] + } + }, { + "name" : "node", + "type" : "SampleNode" + } ] + } + } + } ] + }, { + "type" : "record", + "name" : "SelfRef", + "fields" : [ { + "name" : "something", + "type" : "string" + }, { + "name" : "subNodes", + "type" : { + "type" : "array", + "items" : "SelfRef" + }, + "default" : [ ] + } ] + } ], + "messages" : { } +} + http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/compiler/src/test/java/org/apache/avro/compiler/idl/TestCycle.java ---------------------------------------------------------------------- diff --git a/lang/java/compiler/src/test/java/org/apache/avro/compiler/idl/TestCycle.java b/lang/java/compiler/src/test/java/org/apache/avro/compiler/idl/TestCycle.java new file mode 100644 index 0000000..a38e978 --- /dev/null +++ b/lang/java/compiler/src/test/java/org/apache/avro/compiler/idl/TestCycle.java @@ -0,0 +1,105 @@ +/* + * Copyright 2015 The Apache Software Foundation. + * + * Licensed 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.compiler.idl; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import junit.framework.Assert; +import org.apache.avro.Protocol; +import org.apache.avro.Schema; +import org.apache.avro.compiler.specific.SpecificCompiler; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericDatumReader; +import org.apache.avro.generic.GenericDatumWriter; +import org.apache.avro.generic.GenericRecordBuilder; +import org.apache.avro.io.BinaryDecoder; +import org.apache.avro.io.BinaryEncoder; +import org.apache.avro.io.DecoderFactory; +import org.apache.avro.io.EncoderFactory; +import org.junit.Test; + +/** + * + * @author zoly + */ +public class TestCycle { + + @Test + public void testCycleGeneration() throws ParseException, IOException { + final ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Idl idl = new Idl(cl.getResourceAsStream("input/cycle.avdl"), + "UTF-8"); + Protocol protocol = idl.CompilationUnit(); + String json = protocol.toString(); + System.out.println(json); + + SpecificCompiler compiler = new SpecificCompiler(protocol); + compiler.setStringType(GenericData.StringType.String); + File output = new File("./target"); + compiler.compileToDestination(null, output); + + Map<String, Schema> schemas = new HashMap<String, Schema>(); + for (Schema schema : protocol.getTypes()) { + final String name = schema.getName(); + schemas.put(name, schema); + } + + GenericRecordBuilder rb2 = new GenericRecordBuilder(schemas.get("SampleNode")); + rb2.set("count", 10); + rb2.set("subNodes", Collections.EMPTY_LIST); + GenericData.Record node = rb2.build(); + + GenericRecordBuilder mb = new GenericRecordBuilder(schemas.get("Method")); + mb.set("declaringClass", "Test"); + mb.set("methodName", "test"); + GenericData.Record method = mb.build(); + + GenericRecordBuilder spb = new GenericRecordBuilder(schemas.get("SamplePair")); + spb.set("method", method); + spb.set("node", node); + GenericData.Record sp = spb.build(); + + + GenericRecordBuilder rb = new GenericRecordBuilder(schemas.get("SampleNode")); + rb.set("count", 10); + rb.set("subNodes", Arrays.asList(sp)); + GenericData.Record record = rb.build(); + + serDeserRecord(record); + + } + + private static void serDeserRecord(GenericData.Record data) throws IOException { + ByteArrayOutputStream bab = new ByteArrayOutputStream(); + GenericDatumWriter writer = new GenericDatumWriter(data.getSchema()); + final BinaryEncoder directBinaryEncoder = EncoderFactory.get().directBinaryEncoder(bab, null); + writer.write(data, directBinaryEncoder); + directBinaryEncoder.flush(); + ByteArrayInputStream bis = new ByteArrayInputStream(bab.toByteArray(), 0, bab.size()); + GenericDatumReader reader = new GenericDatumReader(data.getSchema()); + BinaryDecoder directBinaryDecoder = DecoderFactory.get().directBinaryDecoder(bis, null); + GenericData.Record read = (GenericData.Record) reader.read(null, directBinaryDecoder); + Assert.assertEquals(data.toString(), read.toString()); + } + + +} http://git-wip-us.apache.org/repos/asf/avro/blob/1f6fa7b7/lang/java/ipc/nb-configuration.xml ---------------------------------------------------------------------- diff --git a/lang/java/ipc/nb-configuration.xml b/lang/java/ipc/nb-configuration.xml new file mode 100644 index 0000000..93af9a7 --- /dev/null +++ b/lang/java/ipc/nb-configuration.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project-shared-configuration> + <!-- +This file contains additional configuration written by modules in the NetBeans IDE. +The configuration is intended to be shared among all the users of project and +therefore it is assumed to be part of version control checkout. +Without this configuration present, some functionality in the IDE may be limited or fail altogether. +--> + <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> + <!-- +Properties that influence various parts of the IDE, especially code formatting and the like. +You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. +That way multiple projects can share the same settings (useful for formatting rules for example). +Any value defined here will override the pom.xml file value but is only applicable to the current project. +--> + <netbeans.hint.jdkPlatform>JDK_1.6</netbeans.hint.jdkPlatform> + </properties> +</project-shared-configuration>
