Skip to content

Add new method for ObjectReader to bind from JSON Pointer position #866

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 17, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 102 additions & 19 deletions src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
package com.fasterxml.jackson.databind;

import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;

import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.Base64Variant;
import com.fasterxml.jackson.core.FormatSchema;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonPointer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.core.Versioned;
import com.fasterxml.jackson.core.filter.FilteringParserDelegate;
import com.fasterxml.jackson.core.filter.JsonPointerBasedFilter;
import com.fasterxml.jackson.core.filter.TokenFilter;
import com.fasterxml.jackson.core.type.ResolvedType;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
Expand Down Expand Up @@ -69,6 +89,12 @@ public class ObjectReader
*/
protected final boolean _unwrapRoot;

/**
* Filter to be consider for JsonParser.
* Default value to be null as filter not considered.
*/
private final TokenFilter _filter;

/*
/**********************************************************
/* Configuration that can be changed during building
Expand Down Expand Up @@ -178,6 +204,7 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,

_rootDeserializer = _prefetchRootDeserializer(valueType);
_dataFormatReaders = null;
_filter = null;
}

/**
Expand All @@ -204,6 +231,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
_injectableValues = injectableValues;
_unwrapRoot = config.useRootWrapping();
_dataFormatReaders = dataFormatReaders;
_filter = base._filter;
}

/**
Expand All @@ -224,6 +252,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
_injectableValues = base._injectableValues;
_unwrapRoot = config.useRootWrapping();
_dataFormatReaders = base._dataFormatReaders;
_filter = base._filter;
}

protected ObjectReader(ObjectReader base, JsonFactory f)
Expand All @@ -243,6 +272,22 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
_injectableValues = base._injectableValues;
_unwrapRoot = base._unwrapRoot;
_dataFormatReaders = base._dataFormatReaders;
_filter = base._filter;
}

protected ObjectReader(ObjectReader base, TokenFilter filter) {
_config = base._config;
_context = base._context;
_rootDeserializers = base._rootDeserializers;
_parserFactory = base._parserFactory;
_valueType = base._valueType;
_rootDeserializer = base._rootDeserializer;
_valueToUpdate = base._valueToUpdate;
_schema = base._schema;
_injectableValues = base._injectableValues;
_unwrapRoot = base._unwrapRoot;
_dataFormatReaders = base._dataFormatReaders;
_filter = filter;
}

/**
Expand Down Expand Up @@ -1053,7 +1098,8 @@ public <T> T readValue(InputStream src)
if (_dataFormatReaders != null) {
return (T) _detectBindAndClose(_dataFormatReaders.findFormat(src), false);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1069,7 +1115,8 @@ public <T> T readValue(Reader src)
if (_dataFormatReaders != null) {
_reportUndetectableSource(src);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1085,7 +1132,8 @@ public <T> T readValue(String src)
if (_dataFormatReaders != null) {
_reportUndetectableSource(src);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1101,7 +1149,8 @@ public <T> T readValue(byte[] src)
if (_dataFormatReaders != null) {
return (T) _detectBindAndClose(src, 0, src.length);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1117,7 +1166,8 @@ public <T> T readValue(byte[] src, int offset, int length)
if (_dataFormatReaders != null) {
return (T) _detectBindAndClose(src, offset, length);
}
return (T) _bindAndClose(_parserFactory.createParser(src, offset, length));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src, offset, length)));
}

@SuppressWarnings("unchecked")
Expand All @@ -1127,7 +1177,8 @@ public <T> T readValue(File src)
if (_dataFormatReaders != null) {
return (T) _detectBindAndClose(_dataFormatReaders.findFormat(_inputStream(src)), true);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1143,7 +1194,8 @@ public <T> T readValue(URL src)
if (_dataFormatReaders != null) {
return (T) _detectBindAndClose(_dataFormatReaders.findFormat(_inputStream(src)), true);
}
return (T) _bindAndClose(_parserFactory.createParser(src));

return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1160,7 +1212,8 @@ public <T> T readValue(JsonNode src)
if (_dataFormatReaders != null) {
_reportUndetectableSource(src);
}
return (T) _bindAndClose(treeAsTokens(src));

return (T) _bindAndClose(_considerFilter(treeAsTokens(src)));
}

/**
Expand All @@ -1178,7 +1231,8 @@ public JsonNode readTree(InputStream in)
if (_dataFormatReaders != null) {
return _detectBindAndCloseAsTree(in);
}
return _bindAndCloseAsTree(_parserFactory.createParser(in));

return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(in)));
}

/**
Expand All @@ -1196,7 +1250,8 @@ public JsonNode readTree(Reader r)
if (_dataFormatReaders != null) {
_reportUndetectableSource(r);
}
return _bindAndCloseAsTree(_parserFactory.createParser(r));

return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(r)));
}

/**
Expand All @@ -1214,7 +1269,8 @@ public JsonNode readTree(String json)
if (_dataFormatReaders != null) {
_reportUndetectableSource(json);
}
return _bindAndCloseAsTree(_parserFactory.createParser(json));

return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(json)));
}

/*
Expand Down Expand Up @@ -1268,7 +1324,8 @@ public <T> MappingIterator<T> readValues(InputStream src)
if (_dataFormatReaders != null) {
return _detectBindAndReadValues(_dataFormatReaders.findFormat(src), false);
}
return _bindAndReadValues(_parserFactory.createParser(src));

return _bindAndReadValues(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1281,7 +1338,7 @@ public <T> MappingIterator<T> readValues(Reader src)
if (_dataFormatReaders != null) {
_reportUndetectableSource(src);
}
JsonParser p = _parserFactory.createParser(src);
JsonParser p = _considerFilter(_parserFactory.createParser(src));
_initForMultiRead(p);
p.nextToken();
DeserializationContext ctxt = createDeserializationContext(p);
Expand All @@ -1300,7 +1357,7 @@ public <T> MappingIterator<T> readValues(String json)
if (_dataFormatReaders != null) {
_reportUndetectableSource(json);
}
JsonParser p = _parserFactory.createParser(json);
JsonParser p = _considerFilter(_parserFactory.createParser(json));
_initForMultiRead(p);
p.nextToken();
DeserializationContext ctxt = createDeserializationContext(p);
Expand All @@ -1316,7 +1373,7 @@ public <T> MappingIterator<T> readValues(byte[] src, int offset, int length)
if (_dataFormatReaders != null) {
return _detectBindAndReadValues(_dataFormatReaders.findFormat(src, offset, length), false);
}
return _bindAndReadValues(_parserFactory.createParser(src));
return _bindAndReadValues(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1337,7 +1394,7 @@ public <T> MappingIterator<T> readValues(File src)
return _detectBindAndReadValues(
_dataFormatReaders.findFormat(_inputStream(src)), false);
}
return _bindAndReadValues(_parserFactory.createParser(src));
return _bindAndReadValues(_considerFilter(_parserFactory.createParser(src)));
}

/**
Expand All @@ -1352,7 +1409,7 @@ public <T> MappingIterator<T> readValues(URL src)
return _detectBindAndReadValues(
_dataFormatReaders.findFormat(_inputStream(src)), true);
}
return _bindAndReadValues(_parserFactory.createParser(src));
return _bindAndReadValues(_considerFilter(_parserFactory.createParser(src)));
}

/*
Expand Down Expand Up @@ -1422,6 +1479,14 @@ protected Object _bind(JsonParser p, Object valueToUpdate) throws IOException
return result;
}

/**
* Consider filter when creating JsonParser.
*/
protected JsonParser _considerFilter(final JsonParser p) {
return _filter == null || FilteringParserDelegate.class.isInstance(p)
? p : new FilteringParserDelegate(p, _filter, false, false);
}

protected Object _bindAndClose(JsonParser p) throws IOException
{
try {
Expand Down Expand Up @@ -1734,4 +1799,22 @@ protected JsonDeserializer<Object> _prefetchRootDeserializer(JavaType valueType)
}
return deser;
}

/**
* Convenience method to bind from {@link JsonPointer}.
* {@link JsonPointerBasedFilter} is registered and will be used for parsing later.
* @since 2.6
*/
public ObjectReader at(final String value) {
return new ObjectReader(this, new JsonPointerBasedFilter(value));
}

/**
* Convenience method to bind from {@link JsonPointer}
* {@link JsonPointerBasedFilter} is registered and will be used for parsing later.
* @since 2.6
*/
public ObjectReader at(final JsonPointer pointer) {
return new ObjectReader(this, new JsonPointerBasedFilter(pointer));
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package com.fasterxml.jackson.databind.seq;

import com.fasterxml.jackson.core.*;
import java.util.Map;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;

public class ObjectReaderTest extends BaseMapTest
{
final ObjectMapper MAPPER = new ObjectMapper();

static class POJO {
public Map<String, Object> name;
}

public void testParserFeatures() throws Exception
{
final String JSON = "[ /* foo */ 7 ]";
Expand All @@ -28,4 +38,68 @@ public void testParserFeatures() throws Exception
verifyException(e, "foo");
}
}

public void testNoPointerLoading() throws Exception {
final String source = "{\"foo\":{\"bar\":{\"caller\":{\"name\":{\"value\":1234}}}}}";

JsonNode tree = MAPPER.readTree(source);
JsonNode node = tree.at("/foo/bar/caller");
POJO pojo = MAPPER.treeToValue(node, POJO.class);
assertTrue(pojo.name.containsKey("value"));
assertEquals(1234, pojo.name.get("value"));
}

public void testPointerLoading() throws Exception {
final String source = "{\"foo\":{\"bar\":{\"caller\":{\"name\":{\"value\":1234}}}}}";

ObjectReader reader = MAPPER.readerFor(POJO.class).at("/foo/bar/caller");

POJO pojo = reader.readValue(source);
assertTrue(pojo.name.containsKey("value"));
assertEquals(1234, pojo.name.get("value"));
}

public void testPointerLoadingAsJsonNode() throws Exception {
final String source = "{\"foo\":{\"bar\":{\"caller\":{\"name\":{\"value\":1234}}}}}";

ObjectReader reader = MAPPER.readerFor(POJO.class).at("/foo/bar/caller");

JsonNode node = reader.readTree(source);
assertTrue(node.has("name"));
assertEquals("{\"value\":1234}", node.get("name").toString());
}

public void testPointerLoadingMappingIteratorOne() throws Exception {
final String source = "{\"foo\":{\"bar\":{\"caller\":{\"name\":{\"value\":1234}}}}}";

ObjectReader reader = MAPPER.readerFor(POJO.class).at("/foo/bar/caller");

MappingIterator<POJO> itr = reader.readValues(source);

POJO pojo = itr.next();

assertTrue(pojo.name.containsKey("value"));
assertEquals(1234, pojo.name.get("value"));
assertFalse(itr.hasNext());
}

public void testPointerLoadingMappingIteratorMany() throws Exception {
final String source = "{\"foo\":{\"bar\":{\"caller\":[{\"name\":{\"value\":1234}}, {\"name\":{\"value\":5678}}]}}}";

ObjectReader reader = MAPPER.readerFor(POJO.class).at("/foo/bar/caller");

MappingIterator<POJO> itr = reader.readValues(source);

POJO pojo = itr.next();

assertTrue(pojo.name.containsKey("value"));
assertEquals(1234, pojo.name.get("value"));
assertTrue(itr.hasNext());

pojo = itr.next();

assertTrue(pojo.name.containsKey("value"));
assertEquals(5678, pojo.name.get("value"));
assertFalse(itr.hasNext());
}
}