Skip to content

Commit fbe7564

Browse files
committed
Merge branch '2.8'
2 parents 23dc7e5 + 5ebd2e7 commit fbe7564

File tree

4 files changed

+186
-74
lines changed

4 files changed

+186
-74
lines changed

cbor/src/main/java/com/fasterxml/jackson/dataformat/cbor/CBORGenerator.java

+17-15
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/**
1616
* {@link JsonGenerator} implementation that writes CBOR encoded content.
17-
*
17+
*
1818
* @author Tatu Saloranta
1919
*/
2020
public class CBORGenerator extends GeneratorBase
@@ -183,18 +183,18 @@ public int getMask() {
183183
/* Tracking of remaining elements to write
184184
/**********************************************************
185185
*/
186-
186+
187187
protected int[] _elementCounts = NO_INTS;
188188

189189
protected int _elementCountsPtr;
190-
190+
191191
/**
192192
* Number of elements remaining in the current complex structure (if any),
193193
* when writing defined-length Arrays, Objects; marker {@link #INDEFINITE_LENGTH}
194194
* otherwise.
195195
*/
196196
protected int _currentRemainingElements = INDEFINITE_LENGTH;
197-
197+
198198
/*
199199
/**********************************************************
200200
/* Shared String detection
@@ -490,7 +490,7 @@ public final void writeStartArray() throws IOException {
490490
_verifyValueWrite("start an array");
491491
_writeContext = _writeContext.createChildArrayContext();
492492
if (_elementCountsPtr > 0) {
493-
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
493+
_pushRemainingElements();
494494
}
495495
_currentRemainingElements = INDEFINITE_LENGTH;
496496
_writeByte(BYTE_ARRAY_INDEFINITE);
@@ -505,10 +505,7 @@ public final void writeStartArray() throws IOException {
505505
public void writeStartArray(int elementsToWrite) throws IOException {
506506
_verifyValueWrite("start an array");
507507
_writeContext = _writeContext.createChildArrayContext();
508-
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
509-
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
510-
}
511-
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
508+
_pushRemainingElements();
512509
_currentRemainingElements = elementsToWrite;
513510
_writeLengthMarker(PREFIX_TYPE_ARRAY, elementsToWrite);
514511
}
@@ -527,7 +524,7 @@ public final void writeStartObject() throws IOException {
527524
_verifyValueWrite("start an object");
528525
_writeContext = _writeContext.createChildObjectContext();
529526
if (_elementCountsPtr > 0) {
530-
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
527+
_pushRemainingElements();
531528
}
532529
_currentRemainingElements = INDEFINITE_LENGTH;
533530
_writeByte(BYTE_OBJECT_INDEFINITE);
@@ -543,7 +540,7 @@ public final void writeStartObject(Object forValue) throws IOException {
543540
ctxt.setCurrentValue(forValue);
544541
}
545542
if (_elementCountsPtr > 0) {
546-
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
543+
_pushRemainingElements();
547544
}
548545
_currentRemainingElements = INDEFINITE_LENGTH;
549546
_writeByte(BYTE_OBJECT_INDEFINITE);
@@ -552,10 +549,7 @@ public final void writeStartObject(Object forValue) throws IOException {
552549
public final void writeStartObject(int elementsToWrite) throws IOException {
553550
_verifyValueWrite("start an object");
554551
_writeContext = _writeContext.createChildObjectContext();
555-
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
556-
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
557-
}
558-
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
552+
_pushRemainingElements();
559553
_currentRemainingElements = elementsToWrite;
560554
_writeLengthMarker(PREFIX_TYPE_OBJECT, elementsToWrite);
561555
}
@@ -605,6 +599,14 @@ public void writeArray(double[] array, int offset, int length) throws IOExceptio
605599
}
606600
}
607601

602+
// @since 2.8.8
603+
private final void _pushRemainingElements() {
604+
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
605+
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
606+
}
607+
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
608+
}
609+
608610
private final void _writeNumberNoCheck(int i) throws IOException {
609611
int marker;
610612
if (i < 0) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.fasterxml.jackson.dataformat.cbor;
2+
3+
import java.io.ByteArrayOutputStream;
4+
import java.util.*;
5+
6+
import com.fasterxml.jackson.core.JsonGenerator;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
9+
public class GeneratorDeepNestingTest extends CBORTestBase
10+
{
11+
/*
12+
/**********************************************************
13+
/* Test methods
14+
/**********************************************************
15+
*/
16+
17+
final ObjectMapper MAPPER = cborMapper();
18+
19+
// for [dataformats-binary#62]
20+
@SuppressWarnings("unchecked")
21+
public void testDeeplyNestedMap() throws Exception
22+
{
23+
ByteArrayOutputStream out = new ByteArrayOutputStream();
24+
JsonGenerator gen = MAPPER.getFactory().createGenerator(out);
25+
_writeNestedMap(gen, 23);
26+
gen.close();
27+
byte[] encoded = out.toByteArray();
28+
Map<String,Object> result = (Map<String,Object>) MAPPER.readValue(encoded, Map.class);
29+
_verifyNestedMap(result, 23);
30+
}
31+
32+
private void _writeNestedMap(JsonGenerator gen, int levelsLeft) throws Exception
33+
{
34+
if (levelsLeft == 0) {
35+
gen.writeStartObject();
36+
gen.writeEndObject();
37+
return;
38+
}
39+
40+
// exercise different kinds of write methods...
41+
switch (levelsLeft % 3) {
42+
case 0:
43+
gen.writeStartObject();
44+
break;
45+
case 1:
46+
gen.writeStartObject(1);
47+
break;
48+
default:
49+
gen.writeStartObject(gen); // bogus "current" object
50+
break;
51+
}
52+
gen.writeFieldName("level"+levelsLeft);
53+
_writeNestedMap(gen, levelsLeft-1);
54+
gen.writeEndObject();
55+
}
56+
57+
@SuppressWarnings("unchecked")
58+
private void _verifyNestedMap(Map<String,?> map, int level) {
59+
if (level == 0) {
60+
assertEquals(0, map.size());
61+
} else {
62+
assertEquals(1, map.size());
63+
assertEquals("level"+level, map.keySet().iterator().next());
64+
_verifyNestedMap((Map<String,?>) map.values().iterator().next(), level-1);
65+
}
66+
}
67+
68+
public void testDeeplyNestedArray() throws Exception
69+
{
70+
ByteArrayOutputStream out = new ByteArrayOutputStream();
71+
JsonGenerator gen = MAPPER.getFactory().createGenerator(out);
72+
_writeNestedArray(gen, 23);
73+
gen.close();
74+
byte[] encoded = out.toByteArray();
75+
List<?> result = (List<?>) MAPPER.readValue(encoded, List.class);
76+
_verifyNesteArray(result, 23);
77+
}
78+
79+
private void _writeNestedArray(JsonGenerator gen, int levelsLeft) throws Exception
80+
{
81+
if (levelsLeft == 0) {
82+
gen.writeStartArray();
83+
gen.writeEndArray();
84+
return;
85+
}
86+
// exercise different kinds of write methods...
87+
switch (levelsLeft % 2) {
88+
case 0:
89+
gen.writeStartArray();
90+
break;
91+
default:
92+
gen.writeStartArray(2);
93+
break;
94+
}
95+
gen.writeNumber(levelsLeft);
96+
_writeNestedArray(gen, levelsLeft-1);
97+
gen.writeEndArray();
98+
}
99+
100+
private void _verifyNesteArray(List<?> list, int level) {
101+
if (level == 0) {
102+
assertEquals(0, list.size());
103+
} else {
104+
assertEquals(2,list.size());
105+
assertEquals(Integer.valueOf(level), list.get(0));
106+
_verifyNesteArray((List<?>) list.get(1), level-1);
107+
}
108+
}
109+
}

cbor/src/test/java/com/fasterxml/jackson/dataformat/cbor/mapper/BiggerDataTest.java

+59-59
Original file line numberDiff line numberDiff line change
@@ -12,65 +12,65 @@
1212
*/
1313
public class BiggerDataTest extends CBORTestBase
1414
{
15-
static class Citm
16-
{
17-
public Map<Integer,String> areaNames;
18-
public Map<Integer,String> audienceSubCategoryNames;
19-
public Map<Integer,String> blockNames;
20-
public Map<Integer,String> seatCategoryNames;
21-
public Map<Integer,String> subTopicNames;
22-
public Map<Integer,String> subjectNames;
23-
public Map<Integer,String> topicNames;
24-
public Map<Integer,int[]> topicSubTopics;
25-
public Map<String,String> venueNames;
26-
27-
public Map<Integer,Event> events;
28-
public List<Performance> performances;
29-
}
30-
31-
static class Event
32-
{
33-
public int id;
34-
public String name;
35-
public String description;
36-
public String subtitle;
37-
public String logo;
38-
public int subjectCode;
39-
public int[] topicIds;
40-
public LinkedHashSet<Integer> subTopicIds;
41-
}
42-
43-
static class Performance
44-
{
45-
public int id;
46-
public int eventId;
47-
public String name;
48-
public String description;
49-
public String logo;
50-
51-
public List<Price> prices;
52-
public List<SeatCategory> seatCategories;
53-
54-
public long start;
55-
public String seatMapImage;
56-
public String venueCode;
57-
}
58-
59-
static class Price {
60-
public int amount;
61-
public int audienceSubCategoryId;
62-
public int seatCategoryId;
63-
}
64-
65-
static class SeatCategory {
66-
public int seatCategoryId;
67-
public List<Area> areas;
68-
}
69-
70-
static class Area {
71-
public int areaId;
72-
public int[] blockIds;
73-
}
15+
static class Citm
16+
{
17+
public Map<Integer,String> areaNames;
18+
public Map<Integer,String> audienceSubCategoryNames;
19+
public Map<Integer,String> blockNames;
20+
public Map<Integer,String> seatCategoryNames;
21+
public Map<Integer,String> subTopicNames;
22+
public Map<Integer,String> subjectNames;
23+
public Map<Integer,String> topicNames;
24+
public Map<Integer,int[]> topicSubTopics;
25+
public Map<String,String> venueNames;
26+
27+
public Map<Integer,Event> events;
28+
public List<Performance> performances;
29+
}
30+
31+
static class Event
32+
{
33+
public int id;
34+
public String name;
35+
public String description;
36+
public String subtitle;
37+
public String logo;
38+
public int subjectCode;
39+
public int[] topicIds;
40+
public LinkedHashSet<Integer> subTopicIds;
41+
}
42+
43+
static class Performance
44+
{
45+
public int id;
46+
public int eventId;
47+
public String name;
48+
public String description;
49+
public String logo;
50+
51+
public List<Price> prices;
52+
public List<SeatCategory> seatCategories;
53+
54+
public long start;
55+
public String seatMapImage;
56+
public String venueCode;
57+
}
58+
59+
static class Price {
60+
public int amount;
61+
public int audienceSubCategoryId;
62+
public int seatCategoryId;
63+
}
64+
65+
static class SeatCategory {
66+
public int seatCategoryId;
67+
public List<Area> areas;
68+
}
69+
70+
static class Area {
71+
public int areaId;
72+
public int[] blockIds;
73+
}
7474

7575
/*
7676
/**********************************************************

release-notes/VERSION

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Modules:
2424
#54 (protobuf): Some fields are left null
2525
#58 (avro): Regression due to changed namespace of inner enum types
2626
(reported by Peter R)
27+
#62: `java.lang.ArrayIndexOutOfBoundsException` at `CBORGenerator.java`:548
2728

2829
2.8.7 (21-Feb-2017)
2930

0 commit comments

Comments
 (0)