aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCowtowncoder <tatu.saloranta@iki.fi>2015-10-28 16:32:31 -0700
committerCowtowncoder <tatu.saloranta@iki.fi>2015-10-28 16:32:31 -0700
commitfe25f7e14d92f5d4746549e7df22e9af35fdf54b (patch)
tree1009ffb1453383a17223aa6ddc22a3fe0f59b061 /src
parent3bd5de685c1f1116b71e6c51d713528834773fdf (diff)
downloadjackson-databind-fe25f7e14d92f5d4746549e7df22e9af35fdf54b.tar.gz
Fix #984
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java78
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java116
2 files changed, 165 insertions, 29 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java b/src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java
index fc3600ad9..fcf0c3b93 100644
--- a/src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/util/TokenBuffer.java
@@ -436,7 +436,7 @@ public class TokenBuffer
copyCurrentStructure(p);
return this;
}
- /* 28-Oct-2014, tatu: As per #592, need to support a special case of starting from
+ /* 28-Oct-2014, tatu: As per [databind#592], need to support a special case of starting from
* FIELD_NAME, which is taken to mean that we are missing START_OBJECT, but need
* to assume one did exist.
*/
@@ -669,7 +669,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (text == null) {
writeNull();
} else {
- _append(JsonToken.VALUE_STRING, text);
+ _appendValue(JsonToken.VALUE_STRING, text);
}
}
@@ -683,7 +683,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (text == null) {
writeNull();
} else {
- _append(JsonToken.VALUE_STRING, text);
+ _appendValue(JsonToken.VALUE_STRING, text);
}
}
@@ -728,7 +728,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
@Override
public void writeRawValue(String text) throws IOException {
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text));
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text));
}
@Override
@@ -736,12 +736,12 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (offset > 0 || len != text.length()) {
text = text.substring(offset, offset+len);
}
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text));
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new RawValue(text));
}
@Override
public void writeRawValue(char[] text, int offset, int len) throws IOException {
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, new String(text, offset, len));
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, new String(text, offset, len));
}
/*
@@ -752,27 +752,27 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
@Override
public void writeNumber(short i) throws IOException {
- _append(JsonToken.VALUE_NUMBER_INT, Short.valueOf(i));
+ _appendValue(JsonToken.VALUE_NUMBER_INT, Short.valueOf(i));
}
@Override
public void writeNumber(int i) throws IOException {
- _append(JsonToken.VALUE_NUMBER_INT, Integer.valueOf(i));
+ _appendValue(JsonToken.VALUE_NUMBER_INT, Integer.valueOf(i));
}
@Override
public void writeNumber(long l) throws IOException {
- _append(JsonToken.VALUE_NUMBER_INT, Long.valueOf(l));
+ _appendValue(JsonToken.VALUE_NUMBER_INT, Long.valueOf(l));
}
@Override
public void writeNumber(double d) throws IOException {
- _append(JsonToken.VALUE_NUMBER_FLOAT, Double.valueOf(d));
+ _appendValue(JsonToken.VALUE_NUMBER_FLOAT, Double.valueOf(d));
}
@Override
public void writeNumber(float f) throws IOException {
- _append(JsonToken.VALUE_NUMBER_FLOAT, Float.valueOf(f));
+ _appendValue(JsonToken.VALUE_NUMBER_FLOAT, Float.valueOf(f));
}
@Override
@@ -780,7 +780,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (dec == null) {
writeNull();
} else {
- _append(JsonToken.VALUE_NUMBER_FLOAT, dec);
+ _appendValue(JsonToken.VALUE_NUMBER_FLOAT, dec);
}
}
@@ -789,7 +789,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (v == null) {
writeNull();
} else {
- _append(JsonToken.VALUE_NUMBER_INT, v);
+ _appendValue(JsonToken.VALUE_NUMBER_INT, v);
}
}
@@ -798,17 +798,17 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
/* 03-Dec-2010, tatu: related to [JACKSON-423], should try to keep as numeric
* identity as long as possible
*/
- _append(JsonToken.VALUE_NUMBER_FLOAT, encodedValue);
+ _appendValue(JsonToken.VALUE_NUMBER_FLOAT, encodedValue);
}
@Override
public void writeBoolean(boolean state) throws IOException {
- _append(state ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE);
+ _appendValue(state ? JsonToken.VALUE_TRUE : JsonToken.VALUE_FALSE);
}
@Override
public void writeNull() throws IOException {
- _append(JsonToken.VALUE_NULL);
+ _appendValue(JsonToken.VALUE_NULL);
}
/*
@@ -826,7 +826,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
}
Class<?> raw = value.getClass();
if (raw == byte[].class || (value instanceof RawValue)) {
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, value);
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, value);
return;
}
if (_objectCodec == null) {
@@ -834,7 +834,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
* err out, or just embed? For now, do latter.
*/
// throw new JsonMappingException("No ObjectCodec configured for TokenBuffer, writeObject() called");
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, value);
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, value);
} else {
_objectCodec.writeValue(this, value);
}
@@ -850,7 +850,7 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
if (_objectCodec == null) {
// as with 'writeObject()', is codec optional?
- _append(JsonToken.VALUE_EMBEDDED_OBJECT, node);
+ _appendValue(JsonToken.VALUE_EMBEDDED_OBJECT, node);
} else {
_objectCodec.writeTree(this, node);
}
@@ -1082,6 +1082,46 @@ sb.append("NativeObjectIds=").append(_hasNativeObjectIds).append(",");
}
}
+ /**
+ * Similar to {@link #_append(JsonToken)} but also updates context with
+ * knowledge that a scalar value was written
+ *
+ * @since 2.6.4
+ */
+ protected final void _appendValue(JsonToken type)
+ {
+ _writeContext.writeValue();
+ Segment next = _hasNativeId
+ ? _last.append(_appendAt, type, _objectId, _typeId)
+ : _last.append(_appendAt, type);
+ if (next == null) {
+ ++_appendAt;
+ } else {
+ _last = next;
+ _appendAt = 1; // since we added first at 0
+ }
+ }
+
+ /**
+ * Similar to {@link #_append(JsonToken,Object)} but also updates context with
+ * knowledge that a scalar value was written
+ *
+ * @since 2.6.4
+ */
+ protected final void _appendValue(JsonToken type, Object value)
+ {
+ _writeContext.writeValue();
+ Segment next = _hasNativeId
+ ? _last.append(_appendAt, type, value, _objectId, _typeId)
+ : _last.append(_appendAt, type, value);
+ if (next == null) {
+ ++_appendAt;
+ } else {
+ _last = next;
+ _appendAt = 1;
+ }
+ }
+
protected final void _appendRaw(int rawType, Object value)
{
Segment next = _hasNativeId
diff --git a/src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java b/src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java
index 842d617eb..4e14bbf3e 100644
--- a/src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java
+++ b/src/test/java/com/fasterxml/jackson/databind/util/TestTokenBuffer.java
@@ -10,6 +10,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
public class TestTokenBuffer extends BaseMapTest
{
+ private final ObjectMapper MAPPER = objectMapper();
+
/*
/**********************************************************
/* Basic TokenBuffer tests
@@ -219,8 +221,6 @@ public class TestTokenBuffer extends BaseMapTest
// deal with
public void testWithUUID() throws IOException
{
- ObjectMapper mapper = new ObjectMapper();
-
for (String value : new String[] {
"00000007-0000-0000-0000-000000000000",
"76e6d183-5f68-4afa-b94a-922c1fdb83f8",
@@ -229,16 +229,16 @@ public class TestTokenBuffer extends BaseMapTest
"591b2869-146e-41d7-8048-e8131f1fdec5",
"82994ac2-7b23-49f2-8cc5-e24cf6ed77be",
}) {
- TokenBuffer buf = new TokenBuffer(mapper, false); // no ObjectCodec
+ TokenBuffer buf = new TokenBuffer(MAPPER, false); // no ObjectCodec
UUID uuid = UUID.fromString(value);
- mapper.writeValue(buf, uuid);
+ MAPPER.writeValue(buf, uuid);
buf.close();
// and bring it back
- UUID out = mapper.readValue(buf.asParser(), UUID.class);
+ UUID out = MAPPER.readValue(buf.asParser(), UUID.class);
assertEquals(uuid.toString(), out.toString());
- // second part: As per [#362], should NOT use binary with TokenBuffer
+ // second part: As per [databind#362], should NOT use binary with TokenBuffer
JsonParser jp = buf.asParser();
assertEquals(JsonToken.VALUE_STRING, jp.nextToken());
String str = jp.getText();
@@ -246,7 +246,104 @@ public class TestTokenBuffer extends BaseMapTest
jp.close();
}
}
-
+
+ /*
+ /**********************************************************
+ /* Tests for read/output contexts
+ /**********************************************************
+ */
+
+ // for [databind#984]: ensure output context handling identical
+ public void testOutputContext() throws IOException
+ {
+ TokenBuffer buf = new TokenBuffer(null, false); // no ObjectCodec
+ StringWriter w = new StringWriter();
+ JsonGenerator gen = MAPPER.getFactory().createGenerator(w);
+
+ // test content: [{"a":1,"b":{"c":2}},{"a":2,"b":{"c":3}}]
+
+ buf.writeStartArray();
+ gen.writeStartArray();
+ _verifyOutputContext(buf, gen);
+
+ buf.writeStartObject();
+ gen.writeStartObject();
+ _verifyOutputContext(buf, gen);
+
+ buf.writeFieldName("a");
+ gen.writeFieldName("a");
+ _verifyOutputContext(buf, gen);
+
+ buf.writeNumber(1);
+ gen.writeNumber(1);
+ _verifyOutputContext(buf, gen);
+
+ buf.writeFieldName("b");
+ gen.writeFieldName("b");
+ _verifyOutputContext(buf, gen);
+
+ buf.writeStartObject();
+ gen.writeStartObject();
+ _verifyOutputContext(buf, gen);
+
+ buf.writeFieldName("c");
+ gen.writeFieldName("c");
+ _verifyOutputContext(buf, gen);
+
+ buf.writeNumber(2);
+ gen.writeNumber(2);
+ _verifyOutputContext(buf, gen);
+
+ buf.writeEndObject();
+ gen.writeEndObject();
+ _verifyOutputContext(buf, gen);
+
+ buf.writeEndObject();
+ gen.writeEndObject();
+ _verifyOutputContext(buf, gen);
+
+ buf.writeEndArray();
+ gen.writeEndArray();
+ _verifyOutputContext(buf, gen);
+
+ buf.close();
+ gen.close();
+ }
+
+ private void _verifyOutputContext(JsonGenerator gen1, JsonGenerator gen2)
+ {
+ _verifyOutputContext(gen1.getOutputContext(), gen2.getOutputContext());
+ }
+
+ private void _verifyOutputContext(JsonStreamContext ctxt1, JsonStreamContext ctxt2)
+ {
+ if (ctxt1 == null) {
+ if (ctxt2 == null) {
+ return;
+ }
+ fail("Context 1 null, context 2 not null: "+ctxt2);
+ } else if (ctxt2 == null) {
+ fail("Context 2 null, context 1 not null: "+ctxt1);
+ }
+ if (!ctxt1.getTypeDesc().equals(ctxt2.getTypeDesc())) {
+ fail("Different output context: token-buffer's = "+ctxt1+", json-generator's: "+ctxt2);
+ }
+
+ if (ctxt1.inObject()) {
+ assertTrue(ctxt2.inObject());
+ String str1 = ctxt1.getCurrentName();
+ String str2 = ctxt2.getCurrentName();
+
+ if ((str1 != str2) && !str1.equals(str2)) {
+ fail("Expected name '"+str2+"' (JsonParser), TokenBuffer had '"+str1+"'");
+ }
+ } else if (ctxt1.inArray()) {
+ assertTrue(ctxt2.inArray());
+ assertEquals(ctxt1.getCurrentIndex(), ctxt2.getCurrentIndex());
+ }
+ _verifyOutputContext(ctxt1.getParent(), ctxt2.getParent());
+ }
+
/*
/**********************************************************
/* Tests to verify interaction of TokenBuffer and JsonParserSequence
@@ -335,7 +432,7 @@ public class TestTokenBuffer extends BaseMapTest
buf4.close();
}
- // [Issue#743]
+ // [databind#743]
public void testRawValues() throws Exception
{
final String RAW = "{\"a\":1}";
@@ -350,7 +447,6 @@ public class TestTokenBuffer extends BaseMapTest
buf.close();
// then verify it would be serialized just fine
- ObjectMapper mapper = objectMapper();
- assertEquals(RAW, mapper.writeValueAsString(buf));
+ assertEquals(RAW, MAPPER.writeValueAsString(buf));
}
}