[
https://issues.apache.org/jira/browse/AVRO-1667?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15183646#comment-15183646
]
Zoltan Farkas commented on AVRO-1667:
-------------------------------------
I extended, the unit test to complicate the recursiveness, an I am unable to
break my original implementation.
I like your implementation since it does not mutate the fixups... however I
believe in my implementation I was mutating the existing fixups, since the old
ones were not valid fixups anymore?
I still have to re-understand this....
In any case here is the lastest unit test code, I would really like to test and
catch the issue my original implementation had:
{code}
package org.apache.avro.io.parsing;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import junit.framework.Assert;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
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;
public class SymbolTest {
private static final String SCHEMA =
"{\"type\":\"record\",\"name\":\"SampleNode\","
+ "\"namespace\":\"org.spf4j.ssdump2.avro\",\n" +
" \"fields\":[\n" +
" {\"name\":\"count\",\"type\":\"int\",\"default\":0},\n" +
" {\"name\":\"otherNode\",\"type\":[\"null\",\"SampleNode\"], \"default\" :
null},\n" +
" {\"name\":\"subNodes\",\"type\":\n" +
" {\"type\":\"array\",\"items\":{\n" +
" \"type\":\"record\",\"name\":\"SamplePair\",\n" +
" \"fields\":[\n" +
" {\"name\":\"method\",\"type\":\n" +
" {\"type\":\"record\",\"name\":\"Method\",\n" +
" \"fields\":[\n" +
"
{\"name\":\"declaringClass\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},\n"
+
"
{\"name\":\"methodName\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}\n"
+
" ]}},\n" +
" {\"name\":\"node\",\"type\":\"SampleNode\"},"
+ "{\"name\":\"otherNode\",\"type\":\"SampleNode\"}]}}}"
+ ",{\"name\":\"subNodes2\",\"type\":\n" +
" {\"type\":\"array\",\"items\": \"SampleNode\"}}"
+ ",{\"name\":\"subNodes3\",\"type\":\n" +
" {\"type\":\"array\",\"items\": \"SampleNode\"}} ]}";
@Test
public void testValidSymbolTree() throws IOException {
Schema schema = new Schema.Parser().parse(SCHEMA);
Symbol root = Symbol.root(new ResolvingGrammarGenerator()
.generate(schema, schema, new
HashMap<ValidatingGrammarGenerator.LitS, Symbol>()));
validateNonNull(root, new HashSet<Symbol>());
Schema samplePairSchema =
schema.getField("subNodes").schema().getElementType();
Schema methodSchema = samplePairSchema.getField("method").schema();
GenericData.Record method = new GenericData.Record(methodSchema);
method.put("methodName", "m1");
method.put("declaringClass", "c1");
GenericData.Record samplePair = new
GenericData.Record(samplePairSchema);
samplePair.put("method", method);
GenericData.Record sampleNode1 = new GenericData.Record(schema);
sampleNode1.put("subNodes", Collections.EMPTY_LIST);
sampleNode1.put("subNodes2", Collections.EMPTY_LIST);
sampleNode1.put("subNodes3", Collections.EMPTY_LIST);
sampleNode1.put("count", 0);
sampleNode1.put("otherNode", null);
samplePair.put("node", sampleNode1);
samplePair.put("otherNode", sampleNode1);
GenericData.Record sampleNode2 = new GenericData.Record(schema);
sampleNode2.put("subNodes", Arrays.asList(samplePair));
sampleNode2.put("subNodes2", Arrays.asList(sampleNode1));
sampleNode2.put("subNodes3", Arrays.asList(sampleNode1));
sampleNode2.put("count", 0);
sampleNode2.put("otherNode", null);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
GenericDatumWriter writer = new GenericDatumWriter(schema);
BinaryEncoder directBinaryEncoder = new
EncoderFactory().directBinaryEncoder(bos, null);
writer.write(sampleNode2, directBinaryEncoder);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
GenericDatumReader reader = new GenericDatumReader(schema);
BinaryDecoder binaryDecoder = new DecoderFactory().binaryDecoder(bis,
null);
Object read = reader.read(null, binaryDecoder);
System.out.println(read);
Assert.assertEquals(read, sampleNode2);
}
private static void validateNonNull(final Symbol symb, Set<Symbol> seen) {
if (seen.contains(symb)) {
return;
} else {
seen.add(symb);
}
if (symb.production != null) {
for (Symbol s : symb.production) {
if (s == null) {
Assert.fail("invalid parsing tree should not contain
nulls");
}
if (s.kind != Symbol.Kind.ROOT) {
validateNonNull(s, seen);;
}
}
}
}
}
{code}
> Parser symbol tree flattening is broken for recursive schemas
> -------------------------------------------------------------
>
> Key: AVRO-1667
> URL: https://issues.apache.org/jira/browse/AVRO-1667
> Project: Avro
> Issue Type: Bug
> Affects Versions: 1.7.7
> Reporter: Zoltan Farkas
> Attachments: AVRO-1667.2.patch, avro-1667.patch
>
>
> Here is a unit test to reproduce:
> {noformat}
> package org.apache.avro.io.parsing;
> import java.io.IOException;
> import java.util.HashMap;
> import java.util.HashSet;
> import java.util.Set;
> import junit.framework.Assert;
> import org.apache.avro.Schema;
> import org.junit.Test;
> public class SymbolTest {
> private static final String SCHEMA =
> "{\"type\":\"record\",\"name\":\"SampleNode\","
> + "\"namespace\":\"org.spf4j.ssdump2.avro\",\n" +
> " \"fields\":[\n" +
> " {\"name\":\"count\",\"type\":\"int\",\"default\":0},\n" +
> " {\"name\":\"subNodes\",\"type\":\n" +
> " {\"type\":\"array\",\"items\":{\n" +
> " \"type\":\"record\",\"name\":\"SamplePair\",\n" +
> " \"fields\":[\n" +
> " {\"name\":\"method\",\"type\":\n" +
> " {\"type\":\"record\",\"name\":\"Method\",\n" +
> " \"fields\":[\n" +
> "
> {\"name\":\"declaringClass\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},\n"
> +
> "
> {\"name\":\"methodName\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}\n"
> +
> " ]}},\n" +
> " {\"name\":\"node\",\"type\":\"SampleNode\"}]}}}]}";
> @Test
> public void testSomeMethod() throws IOException {
> Schema schema = new Schema.Parser().parse(SCHEMA);
> Symbol root = Symbol.root(new ResolvingGrammarGenerator()
> .generate(schema, schema, new
> HashMap<ValidatingGrammarGenerator.LitS, Symbol>()));
> validateNonNull(root, new HashSet<Symbol>());
> }
> private static void validateNonNull(final Symbol symb, Set<Symbol> seen) {
> if (seen.contains(symb)) {
> return;
> } else {
> seen.add(symb);
> }
> if (symb.production != null) {
> for (Symbol s : symb.production) {
> if (s == null) {
> Assert.fail("invalid parsing tree should not contain
> nulls");
> }
> if (s.kind != Symbol.Kind.ROOT) {
> validateNonNull(s, seen);;
> }
> }
> }
> }
> }
> {noformat}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)