com.github.fge.jackson.JsonNodeReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jackson-coreutils Show documentation
Show all versions of jackson-coreutils Show documentation
JSON Pointer (RFC 6901) and numeric equality for Jackson (2.2.x)
The newest version!
/*
* Copyright (c) 2014, Francis Galiegue ([email protected])
*
* This software is dual-licensed under:
*
* - the Lesser General Public License (LGPL) version 3.0 or, at your option, any
* later version;
* - the Apache Software License (ASL) version 2.0.
*
* The text of this file and of both licenses is available at the root of this
* project or, if you have the jar distribution, in directory META-INF/, under
* the names LGPL-3.0.txt and ASL-2.0.txt respectively.
*
* Direct link to the sources:
*
* - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt
* - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt
*/
package com.github.fge.jackson;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.github.fge.Builder;
import com.github.fge.msgsimple.bundle.MessageBundle;
import com.github.fge.msgsimple.bundle.PropertiesBundle;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
/**
* Class dedicated to reading JSON values from {@link InputStream}s and {@link
* Reader}s
*
* This class wraps a Jackson {@link ObjectMapper} so that it read one, and
* only one, JSON text from a source. By default, when you read and map an
* input source, Jackson will stop after it has read the first valid JSON text;
* this means, for instance, that with this as an input:
*
*
* []]]
*
*
* it will read the initial empty array ({@code []}) and stop there. This
* class, instead, will peek to see whether anything is after the initial array,
* and throw an exception if it finds anything.
*
* Note: the input sources are closed by the read methods.
*
* @see ObjectMapper#readValues(JsonParser, Class)
* @since 1.6
*/
@ThreadSafe
public final class JsonNodeReader
{
private static final MessageBundle BUNDLE
= PropertiesBundle.forPath("/com/github/fge/jackson/jsonNodeReader");
private final ObjectReader reader;
public JsonNodeReader(final ObjectMapper mapper)
{
reader = mapper.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, true)
.readerFor(JsonNode.class);
}
/**
* No-arg constructor (see description)
*/
public JsonNodeReader()
{
this(JacksonUtils.newMapper());
}
/**
* Read a JSON value from an {@link InputStream}
*
* @param in the input stream
* @return the value
* @throws IOException malformed input, or problem encountered when reading
* from the stream
*/
public JsonNode fromInputStream(final InputStream in)
throws IOException
{
JsonParser parser = null;
MappingIterator iterator = null;
try {
parser = reader.getFactory().createParser(in);
iterator = reader.readValues(parser);
return readNode(iterator);
} finally {
if (parser != null) {
parser.close();
}
if (iterator != null) {
iterator.close();
}
}
}
/**
* Read a JSON value from a {@link Reader}
*
* @param r the reader
* @return the value
* @throws IOException malformed input, or problem encountered when reading
* from the reader
*/
public JsonNode fromReader(final Reader r)
throws IOException
{
JsonParser parser = null;
MappingIterator iterator = null;
try {
parser = reader.getFactory().createParser(r);
iterator = reader.readValues(parser);
return readNode(iterator);
} finally {
if (parser != null) {
parser.close();
}
if (iterator != null) {
iterator.close();
}
}
}
private static JsonNode readNode(final MappingIterator iterator)
throws IOException
{
final JsonParser parser = iterator.getParser();
final JsonParseExceptionBuilder builder
= new JsonParseExceptionBuilder(parser);
builder.setMessage(BUNDLE.getMessage("read.noContent"));
if (!iterator.hasNextValue())
throw builder.build();
final JsonNode ret = iterator.nextValue();
builder.setMessage(BUNDLE.getMessage("read.trailingData"))
.setLocation(iterator.getCurrentLocation());
try {
if (iterator.hasNextValue())
throw builder.build();
} catch (JsonParseException e) {
throw builder.setLocation(e.getLocation()).build();
}
return ret;
}
private static final class JsonParseExceptionBuilder
implements Builder
{
private JsonParser parser;
private String message = "";
private JsonLocation location;
private JsonParseExceptionBuilder(@Nonnull final JsonParser parser)
{
BUNDLE.checkNotNull(parser, "read.nullArgument");
this.parser = parser;
location = parser.getCurrentLocation();
}
private JsonParseExceptionBuilder setMessage(
@Nonnull final String message)
{
this.message = BUNDLE.checkNotNull(message, "read.nullArgument");
return this;
}
private JsonParseExceptionBuilder setLocation(
@Nonnull final JsonLocation location)
{
this.location = BUNDLE.checkNotNull(location, "read.nullArgument");
return this;
}
@Override
public JsonParseException build()
{
return new JsonParseException(parser, message, location);
}
}
}