Skip to content

Commit af1e155

Browse files
committed
Fix #38
1 parent d174718 commit af1e155

File tree

4 files changed

+104
-156
lines changed

4 files changed

+104
-156
lines changed

avro/release-notes/VERSION

-134
This file was deleted.

avro/src/main/java/com/fasterxml/jackson/dataformat/avro/deser/RecordReader.java

+29-22
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ final class RecordReader extends AvroStructureReader
1919
private final AvroParserImpl _parser;
2020

2121
protected String _currentName;
22-
22+
2323
protected int _state;
2424
protected final int _count;
25-
25+
2626
public RecordReader(AvroFieldWrapper[] fieldReaders) {
2727
this(null, fieldReaders, null, null);
2828
}
@@ -37,7 +37,7 @@ private RecordReader(AvroReadContext parent,
3737
_parser = parser;
3838
_count = fieldReaders.length;
3939
}
40-
40+
4141
@Override
4242
public RecordReader newReader(AvroReadContext parent,
4343
AvroParserImpl parser, BinaryDecoder decoder) {
@@ -60,26 +60,20 @@ public JsonToken nextToken() throws IOException
6060
return t;
6161
}
6262
case STATE_NAME:
63-
if (_index < _count) {
64-
_currentName = _fieldReaders[_index].getName();
65-
_state = STATE_VALUE;
66-
{
67-
JsonToken t = JsonToken.FIELD_NAME;
68-
_currToken = t;
69-
return t;
70-
}
63+
if (_index >= _count) {
64+
return _nextAtEndObject();
7165
}
72-
// done; fall through
73-
case STATE_END:
74-
_state = STATE_DONE;
75-
_parser.setAvroContext(getParent());
66+
_currentName = _fieldReaders[_index].getName();
67+
_state = STATE_VALUE;
7668
{
77-
JsonToken t = JsonToken.END_OBJECT;
69+
JsonToken t = JsonToken.FIELD_NAME;
7870
_currToken = t;
7971
return t;
8072
}
8173
case STATE_VALUE:
8274
break;
75+
case STATE_END:
76+
return _nextAtEndObject();
8377
case STATE_DONE:
8478
default:
8579
throwIllegalState(_state);
@@ -92,6 +86,22 @@ public JsonToken nextToken() throws IOException
9286
return t;
9387
}
9488

89+
private final JsonToken _nextAtEndObject() throws IOException
90+
{
91+
AvroReadContext parent = getParent();
92+
// as per [dataformats-binary#38], may need to reset, instead of bailing out
93+
if (parent.inRoot()) {
94+
if (!_decoder.isEnd()) {
95+
_state = STATE_START;
96+
_index = 0;
97+
return (_currToken = JsonToken.END_OBJECT);
98+
}
99+
}
100+
_state = STATE_DONE;
101+
_parser.setAvroContext(getParent());
102+
return (_currToken = JsonToken.END_OBJECT);
103+
}
104+
95105
@Override
96106
public String nextFieldName() throws IOException
97107
{
@@ -103,13 +113,10 @@ public String nextFieldName() throws IOException
103113
_currToken = JsonToken.FIELD_NAME;
104114
return name;
105115
}
106-
// falling through to STATE_END handling
107-
_state = STATE_DONE;
108-
_parser.setAvroContext(getParent());
109-
_currToken = JsonToken.END_OBJECT;
110-
return null;
116+
_nextAtEndObject();
117+
} else {
118+
nextToken();
111119
}
112-
nextToken();
113120
return null;
114121
}
115122

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package com.fasterxml.jackson.dataformat.avro;
2+
3+
import java.io.ByteArrayOutputStream;
4+
5+
import com.fasterxml.jackson.databind.MappingIterator;
6+
import com.fasterxml.jackson.databind.SequenceWriter;
7+
8+
import static org.junit.Assert.assertArrayEquals;
9+
10+
/**
11+
* Tests to ensure that it is possible to read a sequence of root-level
12+
* values from a stream.
13+
*/
14+
public class RootSequenceTest extends AvroTestBase
15+
{
16+
public void testReadWriteEmployees() throws Exception
17+
{
18+
AvroMapper mapper = getMapper();
19+
ByteArrayOutputStream b = new ByteArrayOutputStream(1000);
20+
Employee boss = new Employee("Bossman", 55, new String[] { "[email protected]" }, null);
21+
Employee peon1 = new Employee("Worker#1", 24, new String[] { "[email protected]" }, boss);
22+
Employee peon2 = new Employee("Worker#2", 42, new String[] { "[email protected]" }, boss);
23+
24+
// First: write a sequence of 3 root-level Employee Objects
25+
26+
SequenceWriter sw = mapper.writerFor(Employee.class)
27+
.with(getEmployeeSchema())
28+
.writeValues(b);
29+
sw.write(boss);
30+
int curr = b.size();
31+
sw.write(peon1);
32+
int diff = b.size() - curr;
33+
if (diff == 0) {
34+
fail("Should have output more bytes for second entry, did not, total: "+curr);
35+
}
36+
sw.write(peon2);
37+
sw.close();
38+
39+
byte[] bytes = b.toByteArray();
40+
41+
assertNotNull(bytes);
42+
43+
// So far so good: writing seems to work. How about reading?
44+
MappingIterator<Employee> it = mapper.readerFor(Employee.class)
45+
.with(getEmployeeSchema())
46+
.readValues(bytes);
47+
assertTrue(it.hasNextValue());
48+
Employee boss2 = it.nextValue();
49+
assertEquals(boss.age, boss2.age);
50+
assertEquals(boss.name, boss2.name);
51+
assertArrayEquals(boss.emails, boss2.emails);
52+
53+
assertTrue(it.hasNextValue());
54+
Employee worker1 = it.nextValue();
55+
assertEquals(peon1.age, worker1.age);
56+
assertEquals(peon1.name, worker1.name);
57+
assertArrayEquals(peon1.emails, worker1.emails);
58+
59+
assertTrue(it.hasNextValue());
60+
Employee worker2 = it.nextValue();
61+
assertEquals(peon2.age, worker2.age);
62+
assertEquals(peon2.name, worker2.name);
63+
assertArrayEquals(peon2.emails, worker2.emails);
64+
65+
assertFalse(it.hasNextValue());
66+
it.close();
67+
}
68+
}
69+

release-notes/VERSION

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ Modules:
1111

1212
2.9.0 (not yet released)
1313

14+
2.8.7 (not yet released)
15+
16+
#35: Serialization of multiple objects (`SequenceWriter`
17+
(reported by tomvandenberge@github)
18+
#38: Deserialization of multiple (root) values from Avro
19+
1420
2.8.6 (12-Jan-2016)
1521
2.8.5 (14-Nov-2016)
1622

0 commit comments

Comments
 (0)