Skip to content

Commit

Permalink
Implement FasterXML#820
Browse files Browse the repository at this point in the history
  • Loading branch information
Jerry Yang committed Jul 16, 2015
1 parent 5c2ce7a commit bc7fa07
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 21 deletions.
109 changes: 90 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 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,7 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
_injectableValues = base._injectableValues;
_unwrapRoot = base._unwrapRoot;
_dataFormatReaders = base._dataFormatReaders;
_filter = base._filter;
}

/**
Expand Down Expand Up @@ -1053,7 +1083,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 +1100,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 +1117,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 +1134,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 +1151,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 +1162,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 +1179,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 +1197,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 +1216,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 +1235,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 +1254,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 +1309,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 +1323,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 +1342,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 +1358,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 +1379,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 +1394,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 +1464,14 @@ protected Object _bind(JsonParser p, Object valueToUpdate) throws IOException
return result;
}

/**
* Consider filter when creating JsonParser.
*/
private 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 +1784,25 @@ 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) {
_filter = new JsonPointerBasedFilter(value);
return this;
}

/**
* 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) {
_filter = new JsonPointerBasedFilter(pointer);
return this;
}

}
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,49 @@ 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 testPointerLoadingMappingIterator() 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());
}

}

0 comments on commit bc7fa07

Please sign in to comment.