Skip to content

Commit

Permalink
Fix #62
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Mar 20, 2017
1 parent e0bf9eb commit 5ebd2e7
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

/**
* {@link JsonGenerator} implementation that writes CBOR encoded content.
*
*
* @author Tatu Saloranta
*/
public class CBORGenerator extends GeneratorBase
Expand Down Expand Up @@ -183,18 +183,18 @@ public int getMask() {
/* Tracking of remaining elements to write
/**********************************************************
*/

protected int[] _elementCounts = NO_INTS;

protected int _elementCountsPtr;

/**
* Number of elements remaining in the current complex structure (if any),
* when writing defined-length Arrays, Objects; marker {@link #INDEFINITE_LENGTH}
* otherwise.
*/
protected int _currentRemainingElements = INDEFINITE_LENGTH;

/*
/**********************************************************
/* Shared String detection
Expand Down Expand Up @@ -490,7 +490,7 @@ public final void writeStartArray() throws IOException {
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
if (_elementCountsPtr > 0) {
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
_pushRemainingElements();
}
_currentRemainingElements = INDEFINITE_LENGTH;
_writeByte(BYTE_ARRAY_INDEFINITE);
Expand All @@ -505,10 +505,7 @@ public final void writeStartArray() throws IOException {
public void writeStartArray(int elementsToWrite) throws IOException {
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
}
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
_pushRemainingElements();
_currentRemainingElements = elementsToWrite;
_writeLengthMarker(PREFIX_TYPE_ARRAY, elementsToWrite);
}
Expand All @@ -527,7 +524,7 @@ public final void writeStartObject() throws IOException {
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_elementCountsPtr > 0) {
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
_pushRemainingElements();
}
_currentRemainingElements = INDEFINITE_LENGTH;
_writeByte(BYTE_OBJECT_INDEFINITE);
Expand All @@ -543,7 +540,7 @@ public final void writeStartObject(Object forValue) throws IOException {
ctxt.setCurrentValue(forValue);
}
if (_elementCountsPtr > 0) {
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
_pushRemainingElements();
}
_currentRemainingElements = INDEFINITE_LENGTH;
_writeByte(BYTE_OBJECT_INDEFINITE);
Expand All @@ -552,10 +549,7 @@ public final void writeStartObject(Object forValue) throws IOException {
public final void writeStartObject(int elementsToWrite) throws IOException {
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
}
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
_pushRemainingElements();
_currentRemainingElements = elementsToWrite;
_writeLengthMarker(PREFIX_TYPE_OBJECT, elementsToWrite);
}
Expand Down Expand Up @@ -605,6 +599,14 @@ public void writeArray(double[] array, int offset, int length) throws IOExceptio
}
}

// @since 2.8.8
private final void _pushRemainingElements() {
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10);
}
_elementCounts[_elementCountsPtr++] = _currentRemainingElements;
}

private final void _writeNumberNoCheck(int i) throws IOException {
int marker;
if (i < 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.fasterxml.jackson.dataformat.cbor;

import java.io.ByteArrayOutputStream;
import java.util.*;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;

public class GeneratorDeepNestingTest extends CBORTestBase
{
/*
/**********************************************************
/* Test methods
/**********************************************************
*/

final ObjectMapper MAPPER = cborMapper();

// for [dataformats-binary#62]
@SuppressWarnings("unchecked")
public void testDeeplyNestedMap() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
JsonGenerator gen = MAPPER.getFactory().createGenerator(out);
_writeNestedMap(gen, 23);
gen.close();
byte[] encoded = out.toByteArray();
Map<String,Object> result = (Map<String,Object>) MAPPER.readValue(encoded, Map.class);
_verifyNestedMap(result, 23);
}

private void _writeNestedMap(JsonGenerator gen, int levelsLeft) throws Exception
{
if (levelsLeft == 0) {
gen.writeStartObject();
gen.writeEndObject();
return;
}

// exercise different kinds of write methods...
switch (levelsLeft % 3) {
case 0:
gen.writeStartObject();
break;
case 1:
gen.writeStartObject(1);
break;
default:
gen.writeStartObject(gen); // bogus "current" object
break;
}
gen.writeFieldName("level"+levelsLeft);
_writeNestedMap(gen, levelsLeft-1);
gen.writeEndObject();
}

@SuppressWarnings("unchecked")
private void _verifyNestedMap(Map<String,?> map, int level) {
if (level == 0) {
assertEquals(0, map.size());
} else {
assertEquals(1, map.size());
assertEquals("level"+level, map.keySet().iterator().next());
_verifyNestedMap((Map<String,?>) map.values().iterator().next(), level-1);
}
}

public void testDeeplyNestedArray() throws Exception
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
JsonGenerator gen = MAPPER.getFactory().createGenerator(out);
_writeNestedArray(gen, 23);
gen.close();
byte[] encoded = out.toByteArray();
List<?> result = (List<?>) MAPPER.readValue(encoded, List.class);
_verifyNesteArray(result, 23);
}

private void _writeNestedArray(JsonGenerator gen, int levelsLeft) throws Exception
{
if (levelsLeft == 0) {
gen.writeStartArray();
gen.writeEndArray();
return;
}
// exercise different kinds of write methods...
switch (levelsLeft % 2) {
case 0:
gen.writeStartArray();
break;
default:
gen.writeStartArray(2);
break;
}
gen.writeNumber(levelsLeft);
_writeNestedArray(gen, levelsLeft-1);
gen.writeEndArray();
}

private void _verifyNesteArray(List<?> list, int level) {
if (level == 0) {
assertEquals(0, list.size());
} else {
assertEquals(2,list.size());
assertEquals(Integer.valueOf(level), list.get(0));
_verifyNesteArray((List<?>) list.get(1), level-1);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,65 @@
*/
public class BiggerDataTest extends CBORTestBase
{
static class Citm
{
public Map<Integer,String> areaNames;
public Map<Integer,String> audienceSubCategoryNames;
public Map<Integer,String> blockNames;
public Map<Integer,String> seatCategoryNames;
public Map<Integer,String> subTopicNames;
public Map<Integer,String> subjectNames;
public Map<Integer,String> topicNames;
public Map<Integer,int[]> topicSubTopics;
public Map<String,String> venueNames;

public Map<Integer,Event> events;
public List<Performance> performances;
}

static class Event
{
public int id;
public String name;
public String description;
public String subtitle;
public String logo;
public int subjectCode;
public int[] topicIds;
public LinkedHashSet<Integer> subTopicIds;
}

static class Performance
{
public int id;
public int eventId;
public String name;
public String description;
public String logo;

public List<Price> prices;
public List<SeatCategory> seatCategories;

public long start;
public String seatMapImage;
public String venueCode;
}

static class Price {
public int amount;
public int audienceSubCategoryId;
public int seatCategoryId;
}

static class SeatCategory {
public int seatCategoryId;
public List<Area> areas;
}

static class Area {
public int areaId;
public int[] blockIds;
}
static class Citm
{
public Map<Integer,String> areaNames;
public Map<Integer,String> audienceSubCategoryNames;
public Map<Integer,String> blockNames;
public Map<Integer,String> seatCategoryNames;
public Map<Integer,String> subTopicNames;
public Map<Integer,String> subjectNames;
public Map<Integer,String> topicNames;
public Map<Integer,int[]> topicSubTopics;
public Map<String,String> venueNames;

public Map<Integer,Event> events;
public List<Performance> performances;
}

static class Event
{
public int id;
public String name;
public String description;
public String subtitle;
public String logo;
public int subjectCode;
public int[] topicIds;
public LinkedHashSet<Integer> subTopicIds;
}

static class Performance
{
public int id;
public int eventId;
public String name;
public String description;
public String logo;

public List<Price> prices;
public List<SeatCategory> seatCategories;

public long start;
public String seatMapImage;
public String venueCode;
}

static class Price {
public int amount;
public int audienceSubCategoryId;
public int seatCategoryId;
}

static class SeatCategory {
public int seatCategoryId;
public List<Area> areas;
}

static class Area {
public int areaId;
public int[] blockIds;
}

/*
/**********************************************************
Expand Down
1 change: 1 addition & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Modules:
#54 (protobuf): Some fields are left null
#58 (avro): Regression due to changed namespace of inner enum types
(reported by Peter R)
#62: `java.lang.ArrayIndexOutOfBoundsException` at `CBORGenerator.java`:548

2.8.7 (21-Feb-2017)

Expand Down

0 comments on commit 5ebd2e7

Please sign in to comment.