blob: 121ddc2c283cafde27e1215f7c905a5b74401998 [file] [log] [blame]
package org.codehaus.jackson.main;
import java.io.*;
import org.codehaus.jackson.*;
import org.codehaus.jackson.map.MappingJsonFactory;
/**
* Unit tests for verifying that object mapping functionality can
* be accessed using JsonParser.
*/
public class TestParserWithObjects
extends main.BaseTest
{
final static class Pojo
{
int _x;
public void setX(int x) { _x = x; }
}
/*
/**********************************************************
/* Test for simple traversal with data mapping
/**********************************************************
*/
public void testNextValue() throws IOException
{
// Let's test both byte-backed and Reader-based one
_testNextValueBasic(false);
_testNextValueBasic(true);
}
// [JACKSON-395]
public void testNextValueNested() throws IOException
{
// Let's test both byte-backed and Reader-based one
_testNextValueNested(false);
_testNextValueNested(true);
}
public void testPojoReading() throws IOException
{
JsonFactory jf = new MappingJsonFactory();
final String JSON = "{ \"x\" : 9 }";
JsonParser jp = jf.createJsonParser(new StringReader(JSON));
// let's try first by advancing:
assertToken(JsonToken.START_OBJECT, jp.nextToken());
Pojo p = jp.readValueAs(Pojo.class);
assertEquals(9, p._x);
jp.close();
// and without
jp = jf.createJsonParser(new StringReader(JSON));
p = jp.readValueAs(Pojo.class);
assertEquals(9, p._x);
jp.close();
}
public void testReadingArrayAsTree() throws IOException
{
JsonFactory jf = new MappingJsonFactory();
final String JSON = "[ 1, 2, false ]";
for (int i = 0; i < 2; ++i) {
JsonParser jp = jf.createJsonParser(new StringReader(JSON));
// whether to try advancing first or not? Try both
if (i == 0) {
assertToken(JsonToken.START_ARRAY, jp.nextToken());
}
JsonNode root = jp.readValueAsTree();
jp.close();
assertTrue(root.isArray());
assertEquals(3, root.size());
assertEquals(1, root.get(0).getIntValue());
assertEquals(2, root.get(1).getIntValue());
assertFalse(root.get(2).getBooleanValue());
}
}
public void testIsClosed()
throws IOException
{
for (int i = 0; i < 4; ++i) {
String JSON = "[ 1, 2, 3 ]";
boolean stream = ((i & 1) == 0);
JsonParser jp = stream ?
createParserUsingStream(JSON, "UTF-8")
: createParserUsingReader(JSON);
boolean partial = ((i & 2) == 0);
assertFalse(jp.isClosed());
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertFalse(jp.isClosed());
if (partial) {
jp.close();
assertTrue(jp.isClosed());
} else {
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
assertNull(jp.nextToken());
assertTrue(jp.isClosed());
}
}
}
/*
/**********************************************************
/* Tests for data binding
/**********************************************************
*/
/**
* Test similar to above, but instead reads a sequence of values
*/
public void testIncrementalPojoReading()
throws IOException
{
JsonFactory jf = new MappingJsonFactory();
final String JSON = "[ 1, true, null, \"abc\" ]";
JsonParser jp = jf.createJsonParser(new StringReader(JSON));
// let's advance past array start to prevent full binding
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
assertEquals(Integer.valueOf(1), jp.readValueAs(Integer.class));
assertEquals(Boolean.TRUE, jp.readValueAs(Boolean.class));
/* note: null can be returned both when there is no more
* data in current scope, AND when Json null literal is
* bound!
*/
assertNull(jp.readValueAs(Object.class));
// but we can verify that it was Json null by:
assertEquals(JsonToken.VALUE_NULL, jp.getLastClearedToken());
assertEquals("abc", jp.readValueAs(String.class));
// this null is for actually hitting the END_ARRAY
assertNull(jp.readValueAs(Object.class));
assertEquals(JsonToken.END_ARRAY, jp.getLastClearedToken());
// afrer which there should be nothing to advance to:
assertNull(jp.nextToken());
jp.close();
}
public void testPojoReadingFailing()
throws IOException
{
// regular factory can't do it, without a call to setCodec()
JsonFactory jf = new JsonFactory();
try {
final String JSON = "{ \"x\" : 9 }";
JsonParser jp = jf.createJsonParser(new StringReader(JSON));
Pojo p = jp.readValueAs(Pojo.class);
fail("Expected an exception: got "+p);
} catch (IllegalStateException e) {
verifyException(e, "No ObjectCodec defined");
}
}
/*
/**********************************************************
/* Supporting methods
/**********************************************************
*/
private void _testNextValueBasic(boolean useStream) throws IOException
{
// first array, no change to default
JsonParser jp = _getParser("[ 1, 2, 3, 4 ]", useStream);
assertToken(JsonToken.START_ARRAY, jp.nextValue());
for (int i = 1; i <= 4; ++i) {
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextValue());
assertEquals(i, jp.getIntValue());
}
assertToken(JsonToken.END_ARRAY, jp.nextValue());
assertNull(jp.nextValue());
jp.close();
// then Object, is different
jp = _getParser("{ \"3\" :3, \"4\": 4, \"5\" : 5 }", useStream);
assertToken(JsonToken.START_OBJECT, jp.nextValue());
for (int i = 3; i <= 5; ++i) {
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextValue());
assertEquals(String.valueOf(i), jp.getCurrentName());
assertEquals(i, jp.getIntValue());
}
assertToken(JsonToken.END_OBJECT, jp.nextValue());
assertNull(jp.nextValue());
jp.close();
// and then mixed...
jp = _getParser("[ true, [ ], { \"a\" : 3 } ]", useStream);
assertToken(JsonToken.START_ARRAY, jp.nextValue());
assertToken(JsonToken.VALUE_TRUE, jp.nextValue());
assertToken(JsonToken.START_ARRAY, jp.nextValue());
assertToken(JsonToken.END_ARRAY, jp.nextValue());
assertToken(JsonToken.START_OBJECT, jp.nextValue());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextValue());
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.END_OBJECT, jp.nextValue());
assertToken(JsonToken.END_ARRAY, jp.nextValue());
assertNull(jp.nextValue());
jp.close();
}
// [JACKSON-395]
private void _testNextValueNested(boolean useStream) throws IOException
{
// first array, no change to default
JsonParser jp;
// then object with sub-objects...
jp = _getParser("{\"a\": { \"b\" : true, \"c\": false }, \"d\": 3 }", useStream);
assertToken(JsonToken.START_OBJECT, jp.nextValue());
assertNull(jp.getCurrentName());
assertToken(JsonToken.START_OBJECT, jp.nextValue());
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.VALUE_TRUE, jp.nextValue());
assertEquals("b", jp.getCurrentName());
assertToken(JsonToken.VALUE_FALSE, jp.nextValue());
assertEquals("c", jp.getCurrentName());
assertToken(JsonToken.END_OBJECT, jp.nextValue());
// ideally we should match closing marker with field, too:
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextValue());
assertEquals("d", jp.getCurrentName());
assertToken(JsonToken.END_OBJECT, jp.nextValue());
assertNull(jp.getCurrentName());
assertNull(jp.nextValue());
jp.close();
// and arrays
jp = _getParser("{\"a\": [ false ] }", useStream);
assertToken(JsonToken.START_OBJECT, jp.nextValue());
assertNull(jp.getCurrentName());
assertToken(JsonToken.START_ARRAY, jp.nextValue());
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.VALUE_FALSE, jp.nextValue());
assertNull(jp.getCurrentName());
assertToken(JsonToken.END_ARRAY, jp.nextValue());
// ideally we should match closing marker with field, too:
assertEquals("a", jp.getCurrentName());
assertToken(JsonToken.END_OBJECT, jp.nextValue());
assertNull(jp.getCurrentName());
assertNull(jp.nextValue());
jp.close();
}
private JsonParser _getParser(String doc, boolean useStream)
throws IOException
{
JsonFactory jf = new JsonFactory();
if (useStream) {
return jf.createJsonParser(doc.getBytes("UTF-8"));
}
return jf.createJsonParser(new StringReader(doc));
}
}