From 61e892b99f77f43c640a3b7bf33fc3b8a667fddd Mon Sep 17 00:00:00 2001 From: zrlw Date: Thu, 8 Sep 2022 16:08:01 +0800 Subject: [PATCH 01/10] read list by element types --- .../jackson/databind/JsonDeserializer.java | 17 ++- .../jackson/databind/ObjectMapper.java | 107 ++++++++++++------ .../deser/DefaultDeserializationContext.java | 19 +++- .../deser/std/CollectionDeserializer.java | 92 ++++++++++++--- .../jackson/databind/ObjectMapperTest.java | 44 ++++++- 5 files changed, 218 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java index 75e5164d14..688b98c418 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java @@ -2,6 +2,7 @@ import java.io.IOException; import java.util.Collection; +import java.util.List; import com.fasterxml.jackson.core.*; @@ -59,7 +60,7 @@ public abstract class JsonDeserializer * Returned instance is to be constructed by method itself. *

* Pre-condition for this method is that the parser points to the - * first event that is part of value to deserializer (and which + * first event that is part of value to deserializer (and which * is never JSON 'null' literal, more on this below): for simple * types it may be the only value; and for structured types the * Object start marker or a FIELD_NAME. @@ -107,6 +108,11 @@ public abstract class JsonDeserializer public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException; + public T deserializeList(JsonParser p, DeserializationContext ctxt, List elemenTypeList) + throws IOException, JacksonException { + return deserialize(p, ctxt); + } + /** * Alternate deserialization method (compared to the most commonly * used, {@link #deserialize(JsonParser, DeserializationContext)}), @@ -130,6 +136,13 @@ public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) return deserialize(p, ctxt); } + public T deserializeList(JsonParser p, DeserializationContext ctxt, T intoValue, + List elemenTypeList) + throws IOException, JacksonException + { + return deserialize(p, ctxt, intoValue); + } + /** * Deserialization called when type being deserialized is defined to * contain additional type identifier, to allow for correctly @@ -148,7 +161,7 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JacksonException { - // We could try calling + // We could try calling return typeDeserializer.deserializeTypedFromAny(p, ctxt); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index deea44fabb..87452af836 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -68,7 +68,7 @@ // Or if you prefer JSON Tree representation: JsonNode root = mapper.readTree(newState); // and find values by, for example, using a {@link com.fasterxml.jackson.core.JsonPointer} expression: - int age = root.at("/personal/age").getValueAsInt(); + int age = root.at("/personal/age").getValueAsInt(); *

* The main conversion API is defined in {@link ObjectCodec}, so that @@ -77,7 +77,7 @@ * however, usually only for cases where dependency to {@link ObjectMapper} is * either not possible (from Streaming API), or undesireable (when only relying * on Streaming API). - *

+ *

* Mapper instances are fully thread-safe provided that ALL configuration of the * instance occurs before ANY read or write calls. If configuration of a mapper instance * is modified after first usage, changes may or may not take effect, and configuration @@ -114,7 +114,7 @@ *

* Notes on security: use "default typing" feature (see {@link #enableDefaultTyping()}) * is a potential security risk, if used with untrusted content (content generated by - * untrusted external parties). If so, you may want to construct a custom + * untrusted external parties). If so, you may want to construct a custom * {@link TypeResolverBuilder} implementation to limit possible types to instantiate, * (using {@link #setDefaultTyping}). */ @@ -309,7 +309,7 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes) { - return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null; + return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null; } /** @@ -818,7 +818,7 @@ public Version version() { public ObjectMapper registerModule(Module module) { _assertNotNull("module", module); - // Let's ensure we have access to name and version information, + // Let's ensure we have access to name and version information, // even if we do not have immediate use for either. This way we know // that they will be available from beginning String name = module.getModuleName(); @@ -2858,7 +2858,7 @@ public T readValue(JsonParser p, Class valueType) * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" (see ) - * and specifically needs to be used if the root type is a + * and specifically needs to be used if the root type is a * parameterized (generic) container type. * * @throws IOException if a low-level I/O problem (unexpected end-of-input, @@ -2881,7 +2881,7 @@ public T readValue(JsonParser p, TypeReference valueTypeRef) /** * Method to deserialize JSON content into a Java type, reference - * to which is passed as argument. Type is passed using + * to which is passed as argument. Type is passed using * Jackson specific type; instance of which can be constructed using * {@link TypeFactory}. * @@ -3069,7 +3069,7 @@ public MappingIterator readValues(JsonParser p, TypeReference valueTyp * JSON null token is found, it will be represented * as a non-null {@link JsonNode} (one that returns true * for {@link JsonNode#isNull()} - * + * * @throws StreamReadException if underlying input contains invalid content * of type {@link JsonParser} supports (JSON for default case) */ @@ -3227,7 +3227,7 @@ public void writeTree(JsonGenerator g, JsonNode rootNode) * part of core package, whereas impls are part of mapper * package) */ - @Override + @Override public ObjectNode createObjectNode() { return _deserializationConfig.getNodeFactory().objectNode(); } @@ -3515,7 +3515,7 @@ public T readValue(File src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } /** * Method to deserialize JSON content from given file into given Java type. @@ -3535,7 +3535,7 @@ public T readValue(File src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } /** * Method to deserialize JSON content from given file into given Java type. @@ -3581,7 +3581,7 @@ public T readValue(URL src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } /** * Same as {@link #readValue(java.net.URL, Class)} except that target specified by {@link TypeReference}. @@ -3592,7 +3592,7 @@ public T readValue(URL src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } /** * Same as {@link #readValue(java.net.URL, Class)} except that target specified by {@link JavaType}. @@ -3618,7 +3618,7 @@ public T readValue(String content, Class valueType) { _assertNotNull("content", content); return readValue(content, _typeFactory.constructType(valueType)); - } + } /** * Method to deserialize JSON content from given JSON content String. @@ -3633,7 +3633,7 @@ public T readValue(String content, TypeReference valueTypeRef) { _assertNotNull("content", content); return readValue(content, _typeFactory.constructType(valueTypeRef)); - } + } /** * Method to deserialize JSON content from given JSON content String. @@ -3655,7 +3655,19 @@ public T readValue(String content, JavaType valueType) } catch (IOException e) { // shouldn't really happen but being declared need to throw JsonMappingException.fromUnexpectedIOE(e); } - } + } + + public List readValue(String content, List elemenTypeList) + throws JsonProcessingException, JsonMappingException { + _assertNotNull("content", content); + try { // since 2.10 remove "impossible" IOException as per [databind#1675] + return _readMapAndClose(_jsonFactory.createParser(content), elemenTypeList); + } catch (JsonProcessingException e) { + throw e; + } catch (IOException e) { // shouldn't really happen but being declared need to + throw JsonMappingException.fromUnexpectedIOE(e); + } + } @SuppressWarnings("unchecked") public T readValue(Reader src, Class valueType) @@ -3663,7 +3675,7 @@ public T readValue(Reader src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(Reader src, TypeReference valueTypeRef) @@ -3671,7 +3683,7 @@ public T readValue(Reader src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(Reader src, JavaType valueType) @@ -3679,7 +3691,7 @@ public T readValue(Reader src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } + } @SuppressWarnings("unchecked") public T readValue(InputStream src, Class valueType) @@ -3687,7 +3699,7 @@ public T readValue(InputStream src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(InputStream src, TypeReference valueTypeRef) @@ -3695,7 +3707,7 @@ public T readValue(InputStream src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(InputStream src, JavaType valueType) @@ -3703,7 +3715,7 @@ public T readValue(InputStream src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, Class valueType) @@ -3711,16 +3723,16 @@ public T readValue(byte[] src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings("unchecked") - public T readValue(byte[] src, int offset, int len, + public T readValue(byte[] src, int offset, int len, Class valueType) throws IOException, StreamReadException, DatabindException { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(byte[] src, TypeReference valueTypeRef) @@ -3728,7 +3740,7 @@ public T readValue(byte[] src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(byte[] src, int offset, int len, TypeReference valueTypeRef) @@ -3736,7 +3748,7 @@ public T readValue(byte[] src, int offset, int len, TypeReference valueTy { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, JavaType valueType) @@ -3744,7 +3756,7 @@ public T readValue(byte[] src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int len, JavaType valueType) @@ -3752,7 +3764,7 @@ public T readValue(byte[] src, int offset, int len, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), valueType); - } + } @SuppressWarnings("unchecked") public T readValue(DataInput src, Class valueType) throws IOException @@ -4335,7 +4347,7 @@ public ObjectReader reader(TypeReference type) { * Finally, this functionality is not designed to support "advanced" use * cases, such as conversion of polymorphic values, or cases where Object Identity * is used. - * + * * @throws IllegalArgumentException If conversion fails due to incompatible type; * if so, root cause will contain underlying checked exception data binding * functionality threw @@ -4345,7 +4357,7 @@ public T convertValue(Object fromValue, Class toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueType)); - } + } /** * See {@link #convertValue(Object, Class)} @@ -4355,7 +4367,7 @@ public T convertValue(Object fromValue, TypeReference toValueTypeRef) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueTypeRef)); - } + } /** * See {@link #convertValue(Object, Class)} @@ -4365,7 +4377,7 @@ public T convertValue(Object fromValue, JavaType toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, toValueType); - } + } /** * Actual conversion implementation: instead of using existing read @@ -4419,7 +4431,7 @@ protected Object _convert(Object fromValue, JavaType toValueType) /** * Convenience method similar to {@link #convertValue(Object, JavaType)} but one - * in which + * in which *

* Implementation is approximately as follows: *

    @@ -4704,6 +4716,33 @@ protected Object _readMapAndClose(JsonParser p0, JavaType valueType) return result; } } + + @SuppressWarnings("unchecked") + protected List _readMapAndClose(JsonParser p0, List elemenTypeList) + throws IOException + { + try (JsonParser p = p0) { + final List result; + final DeserializationConfig cfg = getDeserializationConfig(); + final DefaultDeserializationContext ctxt = createDeserializationContext(p, cfg); + JavaType valueType = _typeFactory.constructType(List.class); + JsonToken t = _initForReading(p, valueType); + if (t == JsonToken.VALUE_NULL) { + // Ask JsonDeserializer what 'null value' to use: + result = (List) _findRootDeserializer(ctxt, valueType).getNullValue(ctxt); + } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { + result = null; + } else { + result = (List) ctxt.readRootValue(p, valueType, + _findRootDeserializer(ctxt, valueType), null, elemenTypeList); + ctxt.checkUnresolvedObjectId(); + } + if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) { + _verifyNoTrailingTokens(p, ctxt, valueType); + } + return result; + } + } /** * Similar to {@link #_readMapAndClose} but specialized for JsonNode diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 2fcbaa5b52..0f6c36e616 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -315,19 +315,26 @@ public abstract DefaultDeserializationContext createDummyInstance( public Object readRootValue(JsonParser p, JavaType valueType, JsonDeserializer deser, Object valueToUpdate) throws IOException + { + return readRootValue(p, valueType, deser, valueToUpdate, null); + } + + public Object readRootValue(JsonParser p, JavaType valueType, + JsonDeserializer deser, Object valueToUpdate, List elemenTypeList) + throws IOException { if (_config.useRootWrapping()) { - return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate); + return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate, elemenTypeList); } if (valueToUpdate == null) { - return deser.deserialize(p, this); + return deser.deserializeList(p, this, elemenTypeList); } - return deser.deserialize(p, this, valueToUpdate); + return deser.deserializeList(p, this, valueToUpdate, elemenTypeList); } protected Object _unwrapAndDeserialize(JsonParser p, JavaType rootType, JsonDeserializer deser, - Object valueToUpdate) + Object valueToUpdate, List elemenTypeList) throws IOException { PropertyName expRootName = _config.findRootName(rootType); @@ -353,9 +360,9 @@ protected Object _unwrapAndDeserialize(JsonParser p, p.nextToken(); final Object result; if (valueToUpdate == null) { - result = deser.deserialize(p, this); + result = deser.deserializeList(p, this, elemenTypeList); } else { - result = deser.deserialize(p, this, valueToUpdate); + result = deser.deserializeList(p, this, valueToUpdate, elemenTypeList); } // and last, verify that we now get matching END_OBJECT if (p.nextToken() != JsonToken.END_OBJECT) { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java index 42a0f54f6c..94096f638c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java @@ -249,7 +249,31 @@ public Collection deserialize(JsonParser p, DeserializationContext ctxt) if (p.hasToken(JsonToken.VALUE_STRING)) { return _deserializeFromString(p, ctxt, p.getText()); } - return handleNonArray(p, ctxt, createDefaultInstance(ctxt)); + return handleNonArray(p, ctxt, createDefaultInstance(ctxt), null); + } + + @SuppressWarnings("unchecked") + @Override + public Collection deserializeList(JsonParser p, DeserializationContext ctxt, + List elemenTypeList) + throws IOException + { + if (_delegateDeserializer != null) { + return (Collection) _valueInstantiator.createUsingDelegate(ctxt, + _delegateDeserializer.deserializeList(p, ctxt, elemenTypeList)); + } + // 16-May-2020, tatu: As per [dataformats-text#199] need to first check for + // possible Array-coercion and only after that String coercion + if (p.isExpectedStartArrayToken()) { + return _deserializeFromArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); + } + // Empty String may be ok; bit tricky to check, however, since + // there is also possibility of "auto-wrapping" of single-element arrays. + // Hence we only accept empty String here. + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _deserializeFromString(p, ctxt, p.getText(), elemenTypeList); + } + return handleNonArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); } /** @@ -271,7 +295,19 @@ public Collection deserialize(JsonParser p, DeserializationContext ctxt, if (p.isExpectedStartArrayToken()) { return _deserializeFromArray(p, ctxt, result); } - return handleNonArray(p, ctxt, result); + return handleNonArray(p, ctxt, result, null); + } + + @Override + public Collection deserializeList(JsonParser p, DeserializationContext ctxt, + Collection result, List elemenTypeList) + throws IOException + { + // Ok: must point to START_ARRAY (or equivalent) + if (p.isExpectedStartArrayToken()) { + return _deserializeFromArray(p, ctxt, result, elemenTypeList); + } + return handleNonArray(p, ctxt, result, elemenTypeList); } @Override @@ -292,6 +328,14 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, protected Collection _deserializeFromString(JsonParser p, DeserializationContext ctxt, String value) throws IOException + { + return _deserializeFromString(p, ctxt, value, null); + } + + @SuppressWarnings("unchecked") + protected Collection _deserializeFromString(JsonParser p, DeserializationContext ctxt, + String value, List elemenTypeList) + throws IOException { final Class rawTargetType = handledType(); @@ -327,7 +371,7 @@ else if (_isBlank(value)) { // note: `CoercionAction.Fail` falls through because we may need to allow // `ACCEPT_SINGLE_VALUE_AS_ARRAY` handling later on } - return handleNonArray(p, ctxt, createDefaultInstance(ctxt)); + return handleNonArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); } /** @@ -336,29 +380,46 @@ else if (_isBlank(value)) { protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt, Collection result) throws IOException + { + return _deserializeFromArray(p, ctxt, result, null); + } + + protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt, + Collection result, List elemenTypeList) + throws IOException { // [databind#631]: Assign current value, to be accessible by custom serializers p.setCurrentValue(result); - JsonDeserializer valueDes = _valueDeserializer; - // Let's offline handling of values with Object Ids (simplifies code here) - if (valueDes.getObjectIdReader() != null) { - return _deserializeWithObjectId(p, ctxt, result); + JsonDeserializer valueDes = null; + if (null == elemenTypeList) { + valueDes = _valueDeserializer; + // Let's offline handling of values with Object Ids (simplifies code here) + if (valueDes.getObjectIdReader() != null) { + return _deserializeWithObjectId(p, ctxt, result); + } } final TypeDeserializer typeDeser = _valueTypeDeserializer; JsonToken t; + int idx = -1; while ((t = p.nextToken()) != JsonToken.END_ARRAY) { try { + idx++; Object value; if (t == JsonToken.VALUE_NULL) { if (_skipNullValues) { continue; } value = _nullProvider.getNullValue(ctxt); - } else if (typeDeser == null) { - value = valueDes.deserialize(p, ctxt); } else { - value = valueDes.deserializeWithType(p, ctxt, typeDeser); + if (null != elemenTypeList) { + valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(idx), null); + } + if (typeDeser == null) { + value = valueDes.deserialize(p, ctxt); + } else { + value = valueDes.deserializeWithType(p, ctxt, typeDeser); + } } result.add(value); @@ -385,7 +446,7 @@ protected Collection _deserializeFromArray(JsonParser p, Deserialization */ @SuppressWarnings("unchecked") protected final Collection handleNonArray(JsonParser p, DeserializationContext ctxt, - Collection result) + Collection result, List elemenTypeList) throws IOException { // Implicit arrays from single values? @@ -395,7 +456,12 @@ protected final Collection handleNonArray(JsonParser p, DeserializationC if (!canWrap) { return (Collection) ctxt.handleUnexpectedToken(_containerType, p); } - JsonDeserializer valueDes = _valueDeserializer; + JsonDeserializer valueDes = null; + if (null == elemenTypeList) { + valueDes = _valueDeserializer; + } else { + valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(0), null); + } final TypeDeserializer typeDeser = _valueTypeDeserializer; Object value; @@ -430,7 +496,7 @@ protected Collection _deserializeWithObjectId(JsonParser p, Deserializat { // Ok: must point to START_ARRAY (or equivalent) if (!p.isExpectedStartArrayToken()) { - return handleNonArray(p, ctxt, result); + return handleNonArray(p, ctxt, result, null); } // [databind#631]: Assign current value, to be accessible by custom serializers p.setCurrentValue(result); diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java index c465cf3068..6f88c58631 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java @@ -1,8 +1,19 @@ package com.fasterxml.jackson.databind; -import com.fasterxml.jackson.databind.module.SimpleModule; -import java.io.*; -import java.util.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility; import com.fasterxml.jackson.annotation.JsonInclude; @@ -10,14 +21,20 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.JsonTypeName; import com.fasterxml.jackson.annotation.Nulls; -import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.StreamReadFeature; +import com.fasterxml.jackson.core.StreamWriteFeature; import com.fasterxml.jackson.core.json.JsonWriteFeature; import com.fasterxml.jackson.core.util.MinimalPrettyPrinter; - import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector; import com.fasterxml.jackson.databind.introspect.VisibilityChecker; import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.databind.node.*; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.ObjectNode; public class ObjectMapperTest extends BaseMapTest { @@ -544,4 +561,19 @@ public void testHasExplicitTimeZone() throws Exception assertEquals(DEFAULT_TZ, w2.getConfig().getTimeZone()); } } + + public void testReadValueByItemTypes() throws JsonMappingException, JsonProcessingException { + ObjectMapper mapper = new ObjectMapper(); + String content = "[1,2,3,null]"; + List elemenTypeList = new ArrayList<>(); + elemenTypeList.add(mapper.constructType(Integer.class)); + elemenTypeList.add(mapper.constructType(BigDecimal.class)); + elemenTypeList.add(mapper.constructType(Long.class)); + elemenTypeList.add(mapper.constructType(String.class)); + List objectList = mapper.readValue(content, elemenTypeList); + assertEquals(new Integer(1), objectList.get(0)); + assertEquals(new BigDecimal("2"), objectList.get(1)); + assertEquals(new Long(3), objectList.get(2)); + assertEquals(null, objectList.get(3)); + } } From 40f119514fae4801f1dc5ecfc87cc5e054e44d91 Mon Sep 17 00:00:00 2001 From: zrlw Date: Thu, 8 Sep 2022 19:38:38 +0800 Subject: [PATCH 02/10] add readValue methods --- .../jackson/databind/ObjectMapper.java | 97 ++++++++++++++++++- .../deser/DefaultDeserializationContext.java | 28 ++++-- .../std/ArrayBlockingQueueDeserializer.java | 13 ++- .../deser/std/CollectionDeserializer.java | 61 +++++------- 4 files changed, 154 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 87452af836..98321a66f7 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2922,7 +2922,15 @@ public T readValue(JsonParser p, JavaType valueType) _assertNotNull("p", p); return (T) _readValue(getDeserializationConfig(), p, valueType); } - + + @SuppressWarnings("unchecked") + public List readValue(JsonParser p, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("p", p); + return _readValue(getDeserializationConfig(), p, elementTypeList); + } + /** * Method to deserialize JSON content as a tree {@link JsonNode}. * Returns {@link JsonNode} that represents the root of the resulting tree, if there @@ -3557,6 +3565,15 @@ public T readValue(File src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + + @SuppressWarnings("unchecked") + public List readValue(File src, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + /** * Method to deserialize JSON content from given resource into given Java type. *

    @@ -3605,6 +3622,14 @@ public T readValue(URL src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + @SuppressWarnings("unchecked") + public List readValue(URL src, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + /** * Method to deserialize JSON content from given JSON content String. * @@ -3693,6 +3718,14 @@ public T readValue(Reader src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + @SuppressWarnings("unchecked") + public List readValue(Reader src, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + @SuppressWarnings("unchecked") public T readValue(InputStream src, Class valueType) throws IOException, StreamReadException, DatabindException @@ -3717,6 +3750,14 @@ public T readValue(InputStream src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + @SuppressWarnings("unchecked") + public List readValue(InputStream src, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + @SuppressWarnings("unchecked") public T readValue(byte[] src, Class valueType) throws IOException, StreamReadException, DatabindException @@ -3758,6 +3799,14 @@ public T readValue(byte[] src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + @SuppressWarnings("unchecked") + public List readValue(byte[] src, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int len, JavaType valueType) throws IOException, StreamReadException, DatabindException @@ -3766,6 +3815,14 @@ public T readValue(byte[] src, int offset, int len, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), valueType); } + @SuppressWarnings("unchecked") + public List readValue(byte[] src, int offset, int len, List elementTypeList) + throws IOException, StreamReadException, DatabindException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src, offset, len), elementTypeList); + } + @SuppressWarnings("unchecked") public T readValue(DataInput src, Class valueType) throws IOException { @@ -3781,6 +3838,13 @@ public T readValue(DataInput src, JavaType valueType) throws IOException return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } + @SuppressWarnings("unchecked") + public List readValue(DataInput src, List elementTypeList) throws IOException + { + _assertNotNull("src", src); + return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); + } + /* /********************************************************** /* Extended Public API: serialization @@ -4692,6 +4756,35 @@ protected Object _readValue(DeserializationConfig cfg, JsonParser p, return result; } + @SuppressWarnings("unchecked") + protected List _readValue(DeserializationConfig cfg, JsonParser p, + List elementTypeList) + throws IOException + { + // First: may need to read the next token, to initialize + // state (either before first read from parser, or after + // previous token has been cleared) + final List result; + JavaType valueType = _typeFactory.constructType(List.class); + JsonToken t = _initForReading(p, valueType); + final DefaultDeserializationContext ctxt = createDeserializationContext(p, cfg); + if (t == JsonToken.VALUE_NULL) { + // Ask JsonDeserializer what 'null value' to use: + result = (List) _findRootDeserializer(ctxt, valueType).getNullValue(ctxt); + } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { + result = null; + } else { // pointing to event other than null + result = (List) ctxt.readRootValueWithElementTypeList(p, valueType, + _findRootDeserializer(ctxt, valueType), null, elementTypeList); + } + // Need to consume the token too + p.clearCurrentToken(); + if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) { + _verifyNoTrailingTokens(p, ctxt, valueType); + } + return result; + } + protected Object _readMapAndClose(JsonParser p0, JavaType valueType) throws IOException { @@ -4733,7 +4826,7 @@ protected List _readMapAndClose(JsonParser p0, List elemenType } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { result = null; } else { - result = (List) ctxt.readRootValue(p, valueType, + result = (List) ctxt.readRootValueWithElementTypeList(p, valueType, _findRootDeserializer(ctxt, valueType), null, elemenTypeList); ctxt.checkUnresolvedObjectId(); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 0f6c36e616..4c1ade554e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -316,15 +316,15 @@ public Object readRootValue(JsonParser p, JavaType valueType, JsonDeserializer deser, Object valueToUpdate) throws IOException { - return readRootValue(p, valueType, deser, valueToUpdate, null); + return readRootValueWithElementTypeList(p, valueType, deser, valueToUpdate, null); } - public Object readRootValue(JsonParser p, JavaType valueType, + public Object readRootValueWithElementTypeList(JsonParser p, JavaType valueType, JsonDeserializer deser, Object valueToUpdate, List elemenTypeList) throws IOException { if (_config.useRootWrapping()) { - return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate, elemenTypeList); + return _unwrapAndDeserializeWithElementTypeList(p, valueType, deser, valueToUpdate, elemenTypeList); } if (valueToUpdate == null) { return deser.deserializeList(p, this, elemenTypeList); @@ -333,6 +333,14 @@ public Object readRootValue(JsonParser p, JavaType valueType, } protected Object _unwrapAndDeserialize(JsonParser p, + JavaType rootType, JsonDeserializer deser, + Object valueToUpdate) + throws IOException + { + return _unwrapAndDeserializeWithElementTypeList(p, rootType, deser, valueToUpdate, null); + } + + protected Object _unwrapAndDeserializeWithElementTypeList(JsonParser p, JavaType rootType, JsonDeserializer deser, Object valueToUpdate, List elemenTypeList) throws IOException @@ -359,10 +367,18 @@ protected Object _unwrapAndDeserialize(JsonParser p, // ok, then move to value itself.... p.nextToken(); final Object result; - if (valueToUpdate == null) { - result = deser.deserializeList(p, this, elemenTypeList); + if (null == elemenTypeList) { + if (valueToUpdate == null) { + result = deser.deserialize(p, this); + } else { + result = deser.deserialize(p, this, valueToUpdate); + } } else { - result = deser.deserializeList(p, this, valueToUpdate, elemenTypeList); + if (valueToUpdate == null) { + result = deser.deserializeList(p, this, elemenTypeList); + } else { + result = deser.deserializeList(p, this, valueToUpdate, elemenTypeList); + } } // and last, verify that we now get matching END_OBJECT if (p.nextToken() != JsonToken.END_OBJECT) { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java index a27211b9eb..d0880a1a35 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java @@ -90,17 +90,26 @@ protected Collection createDefaultInstance(DeserializationContext ctxt) protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt, Collection result0) throws IOException + { + return _deserializeFromArrayWithElementTypeList(p, ctxt, result0, null); + } + + @Override + protected Collection _deserializeFromArrayWithElementTypeList(JsonParser p, + DeserializationContext ctxt, + Collection result0, List elemenTypeList) + throws IOException { if (result0 == null) { // usual case result0 = new ArrayList<>(); } - result0 = super._deserializeFromArray(p, ctxt, result0); + result0 = super._deserializeFromArrayWithElementTypeList(p, ctxt, result0, elemenTypeList); if (result0.isEmpty()) { return new ArrayBlockingQueue<>(1, false); } return new ArrayBlockingQueue<>(result0.size(), false, result0); } - + @Override public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { // In future could check current token... for now this should be enough: diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java index 94096f638c..60cdf667f9 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java @@ -229,27 +229,11 @@ public ValueInstantiator getValueInstantiator() { /********************************************************** */ - @SuppressWarnings("unchecked") @Override public Collection deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (_delegateDeserializer != null) { - return (Collection) _valueInstantiator.createUsingDelegate(ctxt, - _delegateDeserializer.deserialize(p, ctxt)); - } - // 16-May-2020, tatu: As per [dataformats-text#199] need to first check for - // possible Array-coercion and only after that String coercion - if (p.isExpectedStartArrayToken()) { - return _deserializeFromArray(p, ctxt, createDefaultInstance(ctxt)); - } - // Empty String may be ok; bit tricky to check, however, since - // there is also possibility of "auto-wrapping" of single-element arrays. - // Hence we only accept empty String here. - if (p.hasToken(JsonToken.VALUE_STRING)) { - return _deserializeFromString(p, ctxt, p.getText()); - } - return handleNonArray(p, ctxt, createDefaultInstance(ctxt), null); + return deserializeList(p, ctxt, null); } @SuppressWarnings("unchecked") @@ -265,15 +249,16 @@ public Collection deserializeList(JsonParser p, DeserializationContext c // 16-May-2020, tatu: As per [dataformats-text#199] need to first check for // possible Array-coercion and only after that String coercion if (p.isExpectedStartArrayToken()) { - return _deserializeFromArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); + return _deserializeFromArrayWithElementTypeList(p, ctxt, + createDefaultInstance(ctxt), elemenTypeList); } // Empty String may be ok; bit tricky to check, however, since // there is also possibility of "auto-wrapping" of single-element arrays. // Hence we only accept empty String here. if (p.hasToken(JsonToken.VALUE_STRING)) { - return _deserializeFromString(p, ctxt, p.getText(), elemenTypeList); + return _deserializeFromStringWithElementTypeList(p, ctxt, p.getText(), elemenTypeList); } - return handleNonArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); + return handleNonArrayWithElementTypeList(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); } /** @@ -291,11 +276,7 @@ public Collection deserialize(JsonParser p, DeserializationContext ctxt, Collection result) throws IOException { - // Ok: must point to START_ARRAY (or equivalent) - if (p.isExpectedStartArrayToken()) { - return _deserializeFromArray(p, ctxt, result); - } - return handleNonArray(p, ctxt, result, null); + return deserializeList(p, ctxt, result, null); } @Override @@ -305,9 +286,9 @@ public Collection deserializeList(JsonParser p, DeserializationContext c { // Ok: must point to START_ARRAY (or equivalent) if (p.isExpectedStartArrayToken()) { - return _deserializeFromArray(p, ctxt, result, elemenTypeList); + return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList); } - return handleNonArray(p, ctxt, result, elemenTypeList); + return handleNonArrayWithElementTypeList(p, ctxt, result, elemenTypeList); } @Override @@ -324,16 +305,16 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, * * @since 2.12 */ - @SuppressWarnings("unchecked") protected Collection _deserializeFromString(JsonParser p, DeserializationContext ctxt, String value) throws IOException { - return _deserializeFromString(p, ctxt, value, null); + return _deserializeFromStringWithElementTypeList(p, ctxt, value, null); } @SuppressWarnings("unchecked") - protected Collection _deserializeFromString(JsonParser p, DeserializationContext ctxt, + protected Collection _deserializeFromStringWithElementTypeList(JsonParser p, + DeserializationContext ctxt, String value, List elemenTypeList) throws IOException { @@ -371,7 +352,7 @@ else if (_isBlank(value)) { // note: `CoercionAction.Fail` falls through because we may need to allow // `ACCEPT_SINGLE_VALUE_AS_ARRAY` handling later on } - return handleNonArray(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); + return handleNonArrayWithElementTypeList(p, ctxt, createDefaultInstance(ctxt), elemenTypeList); } /** @@ -381,10 +362,11 @@ protected Collection _deserializeFromArray(JsonParser p, Deserialization Collection result) throws IOException { - return _deserializeFromArray(p, ctxt, result, null); + return _deserializeFromArrayWithElementTypeList(p, ctxt, result, null); } - protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt, + protected Collection _deserializeFromArrayWithElementTypeList(JsonParser p, + DeserializationContext ctxt, Collection result, List elemenTypeList) throws IOException { @@ -399,6 +381,7 @@ protected Collection _deserializeFromArray(JsonParser p, Deserialization return _deserializeWithObjectId(p, ctxt, result); } } + final TypeDeserializer typeDeser = _valueTypeDeserializer; JsonToken t; int idx = -1; @@ -444,8 +427,16 @@ protected Collection _deserializeFromArray(JsonParser p, Deserialization * throw an exception, or try to handle value as if member of implicit * array, depending on configuration. */ - @SuppressWarnings("unchecked") protected final Collection handleNonArray(JsonParser p, DeserializationContext ctxt, + Collection result) + throws IOException + { + return handleNonArrayWithElementTypeList(p, ctxt, result, null); + } + + @SuppressWarnings("unchecked") + protected final Collection handleNonArrayWithElementTypeList(JsonParser p, + DeserializationContext ctxt, Collection result, List elemenTypeList) throws IOException { @@ -496,7 +487,7 @@ protected Collection _deserializeWithObjectId(JsonParser p, Deserializat { // Ok: must point to START_ARRAY (or equivalent) if (!p.isExpectedStartArrayToken()) { - return handleNonArray(p, ctxt, result, null); + return handleNonArray(p, ctxt, result); } // [databind#631]: Assign current value, to be accessible by custom serializers p.setCurrentValue(result); From d70f5c0a42fdf73a88f976f099a0a6badb239ef4 Mon Sep 17 00:00:00 2001 From: zrlw Date: Fri, 9 Sep 2022 08:55:01 +0800 Subject: [PATCH 03/10] optimize deserialization --- .../deser/DefaultDeserializationContext.java | 16 +++++++++++----- .../deser/std/CollectionDeserializer.java | 4 ++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java index 4c1ade554e..7f6d20dc91 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java @@ -327,8 +327,14 @@ public Object readRootValueWithElementTypeList(JsonParser p, JavaType valueType, return _unwrapAndDeserializeWithElementTypeList(p, valueType, deser, valueToUpdate, elemenTypeList); } if (valueToUpdate == null) { + if (null == elemenTypeList) { + return deser.deserialize(p, this); + } return deser.deserializeList(p, this, elemenTypeList); } + if (null == elemenTypeList) { + return deser.deserialize(p, this, valueToUpdate); + } return deser.deserializeList(p, this, valueToUpdate, elemenTypeList); } @@ -367,15 +373,15 @@ protected Object _unwrapAndDeserializeWithElementTypeList(JsonParser p, // ok, then move to value itself.... p.nextToken(); final Object result; - if (null == elemenTypeList) { - if (valueToUpdate == null) { + if (valueToUpdate == null) { + if (null == elemenTypeList) { result = deser.deserialize(p, this); } else { - result = deser.deserialize(p, this, valueToUpdate); + result = deser.deserializeList(p, this, elemenTypeList); } } else { - if (valueToUpdate == null) { - result = deser.deserializeList(p, this, elemenTypeList); + if (null == elemenTypeList) { + result = deser.deserialize(p, this, valueToUpdate); } else { result = deser.deserializeList(p, this, valueToUpdate, elemenTypeList); } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java index 60cdf667f9..ec509906bb 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java @@ -243,6 +243,10 @@ public Collection deserializeList(JsonParser p, DeserializationContext c throws IOException { if (_delegateDeserializer != null) { + if (null == elemenTypeList) { + return (Collection) _valueInstantiator.createUsingDelegate(ctxt, + _delegateDeserializer.deserialize(p, ctxt)); + } return (Collection) _valueInstantiator.createUsingDelegate(ctxt, _delegateDeserializer.deserializeList(p, ctxt, elemenTypeList)); } From 2c1ac2f82aa22e9e848c2741e68eba2a473e1bda Mon Sep 17 00:00:00 2001 From: zrlw Date: Sun, 11 Sep 2022 13:17:21 +0800 Subject: [PATCH 04/10] add readValue method only in ObjectReader --- .../jackson/databind/JsonDeserializer.java | 17 +- .../jackson/databind/ObjectMapper.java | 202 +++----------- .../jackson/databind/ObjectReader.java | 257 ++++++++++++++++-- .../deser/DefaultDeserializationContext.java | 39 +-- .../std/ArrayBlockingQueueDeserializer.java | 13 +- .../deser/std/CollectionDeserializer.java | 119 +++----- .../jackson/databind/ObjectMapperTest.java | 44 +-- .../jackson/databind/ObjectReaderTest.java | 150 +++++++++- 8 files changed, 467 insertions(+), 374 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java index 688b98c418..75e5164d14 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java @@ -2,7 +2,6 @@ import java.io.IOException; import java.util.Collection; -import java.util.List; import com.fasterxml.jackson.core.*; @@ -60,7 +59,7 @@ public abstract class JsonDeserializer * Returned instance is to be constructed by method itself. *

    * Pre-condition for this method is that the parser points to the - * first event that is part of value to deserializer (and which + * first event that is part of value to deserializer (and which * is never JSON 'null' literal, more on this below): for simple * types it may be the only value; and for structured types the * Object start marker or a FIELD_NAME. @@ -108,11 +107,6 @@ public abstract class JsonDeserializer public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException; - public T deserializeList(JsonParser p, DeserializationContext ctxt, List elemenTypeList) - throws IOException, JacksonException { - return deserialize(p, ctxt); - } - /** * Alternate deserialization method (compared to the most commonly * used, {@link #deserialize(JsonParser, DeserializationContext)}), @@ -136,13 +130,6 @@ public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) return deserialize(p, ctxt); } - public T deserializeList(JsonParser p, DeserializationContext ctxt, T intoValue, - List elemenTypeList) - throws IOException, JacksonException - { - return deserialize(p, ctxt, intoValue); - } - /** * Deserialization called when type being deserialized is defined to * contain additional type identifier, to allow for correctly @@ -161,7 +148,7 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JacksonException { - // We could try calling + // We could try calling return typeDeserializer.deserializeTypedFromAny(p, ctxt); } diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 98321a66f7..deea44fabb 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -68,7 +68,7 @@ // Or if you prefer JSON Tree representation: JsonNode root = mapper.readTree(newState); // and find values by, for example, using a {@link com.fasterxml.jackson.core.JsonPointer} expression: - int age = root.at("/personal/age").getValueAsInt(); + int age = root.at("/personal/age").getValueAsInt(); *

    * The main conversion API is defined in {@link ObjectCodec}, so that @@ -77,7 +77,7 @@ * however, usually only for cases where dependency to {@link ObjectMapper} is * either not possible (from Streaming API), or undesireable (when only relying * on Streaming API). - *

    + *

    * Mapper instances are fully thread-safe provided that ALL configuration of the * instance occurs before ANY read or write calls. If configuration of a mapper instance * is modified after first usage, changes may or may not take effect, and configuration @@ -114,7 +114,7 @@ *

    * Notes on security: use "default typing" feature (see {@link #enableDefaultTyping()}) * is a potential security risk, if used with untrusted content (content generated by - * untrusted external parties). If so, you may want to construct a custom + * untrusted external parties). If so, you may want to construct a custom * {@link TypeResolverBuilder} implementation to limit possible types to instantiate, * (using {@link #setDefaultTyping}). */ @@ -309,7 +309,7 @@ public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection subtypes) { - return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null; + return useForType(baseType) ? super.buildTypeSerializer(config, baseType, subtypes) : null; } /** @@ -818,7 +818,7 @@ public Version version() { public ObjectMapper registerModule(Module module) { _assertNotNull("module", module); - // Let's ensure we have access to name and version information, + // Let's ensure we have access to name and version information, // even if we do not have immediate use for either. This way we know // that they will be available from beginning String name = module.getModuleName(); @@ -2858,7 +2858,7 @@ public T readValue(JsonParser p, Class valueType) * Method to deserialize JSON content into a Java type, reference * to which is passed as argument. Type is passed using so-called * "super type token" (see ) - * and specifically needs to be used if the root type is a + * and specifically needs to be used if the root type is a * parameterized (generic) container type. * * @throws IOException if a low-level I/O problem (unexpected end-of-input, @@ -2881,7 +2881,7 @@ public T readValue(JsonParser p, TypeReference valueTypeRef) /** * Method to deserialize JSON content into a Java type, reference - * to which is passed as argument. Type is passed using + * to which is passed as argument. Type is passed using * Jackson specific type; instance of which can be constructed using * {@link TypeFactory}. * @@ -2922,15 +2922,7 @@ public T readValue(JsonParser p, JavaType valueType) _assertNotNull("p", p); return (T) _readValue(getDeserializationConfig(), p, valueType); } - - @SuppressWarnings("unchecked") - public List readValue(JsonParser p, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("p", p); - return _readValue(getDeserializationConfig(), p, elementTypeList); - } - + /** * Method to deserialize JSON content as a tree {@link JsonNode}. * Returns {@link JsonNode} that represents the root of the resulting tree, if there @@ -3077,7 +3069,7 @@ public MappingIterator readValues(JsonParser p, TypeReference valueTyp * JSON null token is found, it will be represented * as a non-null {@link JsonNode} (one that returns true * for {@link JsonNode#isNull()} - * + * * @throws StreamReadException if underlying input contains invalid content * of type {@link JsonParser} supports (JSON for default case) */ @@ -3235,7 +3227,7 @@ public void writeTree(JsonGenerator g, JsonNode rootNode) * part of core package, whereas impls are part of mapper * package) */ - @Override + @Override public ObjectNode createObjectNode() { return _deserializationConfig.getNodeFactory().objectNode(); } @@ -3523,7 +3515,7 @@ public T readValue(File src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } /** * Method to deserialize JSON content from given file into given Java type. @@ -3543,7 +3535,7 @@ public T readValue(File src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } /** * Method to deserialize JSON content from given file into given Java type. @@ -3565,15 +3557,6 @@ public T readValue(File src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } - - @SuppressWarnings("unchecked") - public List readValue(File src, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } - /** * Method to deserialize JSON content from given resource into given Java type. *

    @@ -3598,7 +3581,7 @@ public T readValue(URL src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } /** * Same as {@link #readValue(java.net.URL, Class)} except that target specified by {@link TypeReference}. @@ -3609,7 +3592,7 @@ public T readValue(URL src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } /** * Same as {@link #readValue(java.net.URL, Class)} except that target specified by {@link JavaType}. @@ -3622,14 +3605,6 @@ public T readValue(URL src, JavaType valueType) return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } - @SuppressWarnings("unchecked") - public List readValue(URL src, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } - /** * Method to deserialize JSON content from given JSON content String. * @@ -3643,7 +3618,7 @@ public T readValue(String content, Class valueType) { _assertNotNull("content", content); return readValue(content, _typeFactory.constructType(valueType)); - } + } /** * Method to deserialize JSON content from given JSON content String. @@ -3658,7 +3633,7 @@ public T readValue(String content, TypeReference valueTypeRef) { _assertNotNull("content", content); return readValue(content, _typeFactory.constructType(valueTypeRef)); - } + } /** * Method to deserialize JSON content from given JSON content String. @@ -3680,19 +3655,7 @@ public T readValue(String content, JavaType valueType) } catch (IOException e) { // shouldn't really happen but being declared need to throw JsonMappingException.fromUnexpectedIOE(e); } - } - - public List readValue(String content, List elemenTypeList) - throws JsonProcessingException, JsonMappingException { - _assertNotNull("content", content); - try { // since 2.10 remove "impossible" IOException as per [databind#1675] - return _readMapAndClose(_jsonFactory.createParser(content), elemenTypeList); - } catch (JsonProcessingException e) { - throw e; - } catch (IOException e) { // shouldn't really happen but being declared need to - throw JsonMappingException.fromUnexpectedIOE(e); - } - } + } @SuppressWarnings("unchecked") public T readValue(Reader src, Class valueType) @@ -3700,7 +3663,7 @@ public T readValue(Reader src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(Reader src, TypeReference valueTypeRef) @@ -3708,7 +3671,7 @@ public T readValue(Reader src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(Reader src, JavaType valueType) @@ -3716,15 +3679,7 @@ public T readValue(Reader src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } - - @SuppressWarnings("unchecked") - public List readValue(Reader src, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } + } @SuppressWarnings("unchecked") public T readValue(InputStream src, Class valueType) @@ -3732,7 +3687,7 @@ public T readValue(InputStream src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(InputStream src, TypeReference valueTypeRef) @@ -3740,7 +3695,7 @@ public T readValue(InputStream src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(InputStream src, JavaType valueType) @@ -3748,15 +3703,7 @@ public T readValue(InputStream src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } - - @SuppressWarnings("unchecked") - public List readValue(InputStream src, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, Class valueType) @@ -3764,16 +3711,16 @@ public T readValue(byte[] src, Class valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings("unchecked") - public T readValue(byte[] src, int offset, int len, + public T readValue(byte[] src, int offset, int len, Class valueType) throws IOException, StreamReadException, DatabindException { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), _typeFactory.constructType(valueType)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(byte[] src, TypeReference valueTypeRef) @@ -3781,7 +3728,7 @@ public T readValue(byte[] src, TypeReference valueTypeRef) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings({ "unchecked" }) public T readValue(byte[] src, int offset, int len, TypeReference valueTypeRef) @@ -3789,7 +3736,7 @@ public T readValue(byte[] src, int offset, int len, TypeReference valueTy { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), _typeFactory.constructType(valueTypeRef)); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, JavaType valueType) @@ -3797,15 +3744,7 @@ public T readValue(byte[] src, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); - } - - @SuppressWarnings("unchecked") - public List readValue(byte[] src, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } + } @SuppressWarnings("unchecked") public T readValue(byte[] src, int offset, int len, JavaType valueType) @@ -3813,15 +3752,7 @@ public T readValue(byte[] src, int offset, int len, JavaType valueType) { _assertNotNull("src", src); return (T) _readMapAndClose(_jsonFactory.createParser(src, offset, len), valueType); - } - - @SuppressWarnings("unchecked") - public List readValue(byte[] src, int offset, int len, List elementTypeList) - throws IOException, StreamReadException, DatabindException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src, offset, len), elementTypeList); - } + } @SuppressWarnings("unchecked") public T readValue(DataInput src, Class valueType) throws IOException @@ -3838,13 +3769,6 @@ public T readValue(DataInput src, JavaType valueType) throws IOException return (T) _readMapAndClose(_jsonFactory.createParser(src), valueType); } - @SuppressWarnings("unchecked") - public List readValue(DataInput src, List elementTypeList) throws IOException - { - _assertNotNull("src", src); - return _readMapAndClose(_jsonFactory.createParser(src), elementTypeList); - } - /* /********************************************************** /* Extended Public API: serialization @@ -4411,7 +4335,7 @@ public ObjectReader reader(TypeReference type) { * Finally, this functionality is not designed to support "advanced" use * cases, such as conversion of polymorphic values, or cases where Object Identity * is used. - * + * * @throws IllegalArgumentException If conversion fails due to incompatible type; * if so, root cause will contain underlying checked exception data binding * functionality threw @@ -4421,7 +4345,7 @@ public T convertValue(Object fromValue, Class toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueType)); - } + } /** * See {@link #convertValue(Object, Class)} @@ -4431,7 +4355,7 @@ public T convertValue(Object fromValue, TypeReference toValueTypeRef) throws IllegalArgumentException { return (T) _convert(fromValue, _typeFactory.constructType(toValueTypeRef)); - } + } /** * See {@link #convertValue(Object, Class)} @@ -4441,7 +4365,7 @@ public T convertValue(Object fromValue, JavaType toValueType) throws IllegalArgumentException { return (T) _convert(fromValue, toValueType); - } + } /** * Actual conversion implementation: instead of using existing read @@ -4495,7 +4419,7 @@ protected Object _convert(Object fromValue, JavaType toValueType) /** * Convenience method similar to {@link #convertValue(Object, JavaType)} but one - * in which + * in which *

    * Implementation is approximately as follows: *

      @@ -4756,35 +4680,6 @@ protected Object _readValue(DeserializationConfig cfg, JsonParser p, return result; } - @SuppressWarnings("unchecked") - protected List _readValue(DeserializationConfig cfg, JsonParser p, - List elementTypeList) - throws IOException - { - // First: may need to read the next token, to initialize - // state (either before first read from parser, or after - // previous token has been cleared) - final List result; - JavaType valueType = _typeFactory.constructType(List.class); - JsonToken t = _initForReading(p, valueType); - final DefaultDeserializationContext ctxt = createDeserializationContext(p, cfg); - if (t == JsonToken.VALUE_NULL) { - // Ask JsonDeserializer what 'null value' to use: - result = (List) _findRootDeserializer(ctxt, valueType).getNullValue(ctxt); - } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { - result = null; - } else { // pointing to event other than null - result = (List) ctxt.readRootValueWithElementTypeList(p, valueType, - _findRootDeserializer(ctxt, valueType), null, elementTypeList); - } - // Need to consume the token too - p.clearCurrentToken(); - if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) { - _verifyNoTrailingTokens(p, ctxt, valueType); - } - return result; - } - protected Object _readMapAndClose(JsonParser p0, JavaType valueType) throws IOException { @@ -4809,33 +4704,6 @@ protected Object _readMapAndClose(JsonParser p0, JavaType valueType) return result; } } - - @SuppressWarnings("unchecked") - protected List _readMapAndClose(JsonParser p0, List elemenTypeList) - throws IOException - { - try (JsonParser p = p0) { - final List result; - final DeserializationConfig cfg = getDeserializationConfig(); - final DefaultDeserializationContext ctxt = createDeserializationContext(p, cfg); - JavaType valueType = _typeFactory.constructType(List.class); - JsonToken t = _initForReading(p, valueType); - if (t == JsonToken.VALUE_NULL) { - // Ask JsonDeserializer what 'null value' to use: - result = (List) _findRootDeserializer(ctxt, valueType).getNullValue(ctxt); - } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { - result = null; - } else { - result = (List) ctxt.readRootValueWithElementTypeList(p, valueType, - _findRootDeserializer(ctxt, valueType), null, elemenTypeList); - ctxt.checkUnresolvedObjectId(); - } - if (cfg.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) { - _verifyNoTrailingTokens(p, ctxt, valueType); - } - return result; - } - } /** * Similar to {@link #_readMapAndClose} but specialized for JsonNode diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java index b64a0527ee..ab28bb146d 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java @@ -13,12 +13,14 @@ import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion; import com.fasterxml.jackson.core.type.ResolvedType; import com.fasterxml.jackson.core.type.TypeReference; - +import com.fasterxml.jackson.databind.cfg.CoercionAction; +import com.fasterxml.jackson.databind.cfg.CoercionInputShape; import com.fasterxml.jackson.databind.cfg.ContextAttributes; import com.fasterxml.jackson.databind.cfg.DatatypeFeature; import com.fasterxml.jackson.databind.deser.DataFormatReaders; import com.fasterxml.jackson.databind.deser.DefaultDeserializationContext; import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; +import com.fasterxml.jackson.databind.deser.std.CollectionDeserializer; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.TreeTraversingParser; import com.fasterxml.jackson.databind.type.TypeFactory; @@ -77,7 +79,7 @@ public class ObjectReader protected final boolean _unwrapRoot; /** - * Filter to be consider for JsonParser. + * Filter to be consider for JsonParser. * Default value to be null as filter not considered. */ private final TokenFilter _filter; @@ -192,7 +194,7 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config, _unwrapRoot = config.useRootWrapping(); _rootDeserializer = _prefetchRootDeserializer(valueType); - _dataFormatReaders = null; + _dataFormatReaders = null; _filter = null; } @@ -401,7 +403,7 @@ public ObjectReader with(DeserializationFeature first, DeserializationFeature... other) { return _with(_config.with(first, other)); - } + } /** * Method for constructing a new reader instance that is configured @@ -409,14 +411,14 @@ public ObjectReader with(DeserializationFeature first, */ public ObjectReader withFeatures(DeserializationFeature... features) { return _with(_config.withFeatures(features)); - } + } /** * Method for constructing a new reader instance that is configured * with specified feature disabled. */ public ObjectReader without(DeserializationFeature feature) { - return _with(_config.without(feature)); + return _with(_config.without(feature)); } /** @@ -426,7 +428,7 @@ public ObjectReader without(DeserializationFeature feature) { public ObjectReader without(DeserializationFeature first, DeserializationFeature... other) { return _with(_config.without(first, other)); - } + } /** * Method for constructing a new reader instance that is configured @@ -434,7 +436,7 @@ public ObjectReader without(DeserializationFeature first, */ public ObjectReader withoutFeatures(DeserializationFeature... features) { return _with(_config.withoutFeatures(features)); - } + } /* /********************************************************************** @@ -460,7 +462,7 @@ public ObjectReader with(DatatypeFeature feature) { */ public ObjectReader withFeatures(DatatypeFeature... features) { return _with(_config.withFeatures(features)); - } + } /** * Method for constructing a new reader instance that is configured @@ -469,7 +471,7 @@ public ObjectReader withFeatures(DatatypeFeature... features) { * @since 2.14 */ public ObjectReader without(DatatypeFeature feature) { - return _with(_config.without(feature)); + return _with(_config.without(feature)); } /** @@ -480,7 +482,7 @@ public ObjectReader without(DatatypeFeature feature) { */ public ObjectReader withoutFeatures(DatatypeFeature... features) { return _with(_config.withoutFeatures(features)); - } + } /* /********************************************************** @@ -511,7 +513,7 @@ public ObjectReader with(JsonParser.Feature feature) { */ public ObjectReader withFeatures(JsonParser.Feature... features) { return _with(_config.withFeatures(features)); - } + } /** * Method for constructing a new reader instance that is configured @@ -522,7 +524,7 @@ public ObjectReader withFeatures(JsonParser.Feature... features) { * @return Reader instance with specified feature disabled */ public ObjectReader without(JsonParser.Feature feature) { - return _with(_config.without(feature)); + return _with(_config.without(feature)); } /** @@ -591,7 +593,7 @@ public ObjectReader with(FormatFeature feature) { */ public ObjectReader withFeatures(FormatFeature... features) { return _with(_config.withFeatures(features)); - } + } /** * Method for constructing a new reader instance that is configured @@ -600,7 +602,7 @@ public ObjectReader withFeatures(FormatFeature... features) { * @since 2.7 */ public ObjectReader without(FormatFeature feature) { - return _with(_config.without(feature)); + return _with(_config.without(feature)); } /** @@ -620,8 +622,8 @@ public ObjectReader withoutFeatures(FormatFeature... features) { */ /** - * Convenience method to bind from {@link JsonPointer}. - * {@link JsonPointerBasedFilter} is registered and will be used for parsing later. + * 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 pointerExpr) { @@ -648,7 +650,7 @@ public ObjectReader at(final JsonPointer pointer) { */ public ObjectReader with(DeserializationConfig config) { return _with(config); - } + } /** * Method for constructing a new instance with configuration that uses @@ -776,7 +778,7 @@ public ObjectReader forType(JavaType valueType) } return _new(this, _config, valueType, rootDeser, _valueToUpdate, _schema, _injectableValues, det); - } + } /** * Method for constructing a new reader instance that is configured @@ -789,7 +791,7 @@ public ObjectReader forType(JavaType valueType) */ public ObjectReader forType(Class valueType) { return forType(_config.constructType(valueType)); - } + } /** * Method for constructing a new reader instance that is configured @@ -802,7 +804,7 @@ public ObjectReader forType(Class valueType) { */ public ObjectReader forType(TypeReference valueTypeRef) { return forType(_config.getTypeFactory().constructType(valueTypeRef.getType())); - } + } /** * @deprecated since 2.5 Use {@link #forType(JavaType)} instead @@ -818,7 +820,7 @@ public ObjectReader withType(JavaType valueType) { @Deprecated public ObjectReader withType(Class valueType) { return forType(_config.constructType(valueType)); - } + } /** * @deprecated since 2.5 Use {@link #forType(Class)} instead @@ -834,11 +836,11 @@ public ObjectReader withType(java.lang.reflect.Type valueType) { @Deprecated public ObjectReader withType(TypeReference valueTypeRef) { return forType(_config.getTypeFactory().constructType(valueTypeRef.getType())); - } + } /** * Method for constructing a new instance with configuration that - * updates passed Object (as root value), instead of constructing + * updates passed Object (as root value), instead of constructing * a new value. *

      * Note that the method does NOT change state of this reader, but @@ -1294,6 +1296,207 @@ public T readValue(JsonParser p, JavaType valueType) throws IOException { return (T) forType(valueType).readValue(p); } + @SuppressWarnings("unchecked") + public List readValue(JsonParser p, List elementTypeList) throws IOException { + JavaType valueType = _config.constructType(List.class); + if (!valueType.equals(_valueType)) { + return forType(valueType).readValue(p, elementTypeList); + } + _assertNotNull("p", p); + _assertNotNull("elementTypeList", elementTypeList); + List result; + final DefaultDeserializationContext ctxt = createDeserializationContext(p); + JsonToken t = _initForReading(ctxt, p); + if (t == JsonToken.VALUE_NULL) { + if (_valueToUpdate == null) { + result = (List) _findRootDeserializer(ctxt).getNullValue(ctxt); + } else { + result = (List)_valueToUpdate; + } + } else if (t == JsonToken.END_ARRAY || t == JsonToken.END_OBJECT) { + result = (List) _valueToUpdate; + } else { // pointing to event other than null + CollectionDeserializer deser = + (CollectionDeserializer) ((JsonDeserializer) _findRootDeserializer(ctxt)); + if (_config.useRootWrapping()) { + return _unwrapAndDeserializeWithElementTypeList( + p, ctxt, valueType, deser, _valueToUpdate, elementTypeList); + } + if (_valueToUpdate == null) { + return deserializeList(deser, p, ctxt, elementTypeList); + } + return deserializeList(deser, p, ctxt, (List) _valueToUpdate, elementTypeList); + } + // Need to consume the token too + p.clearCurrentToken(); + if (_config.isEnabled(DeserializationFeature.FAIL_ON_TRAILING_TOKENS)) { + _verifyNoTrailingTokens(p, ctxt, _valueType); + } + return result; + } + + @SuppressWarnings("unchecked") + protected List _unwrapAndDeserializeWithElementTypeList(JsonParser p, + DefaultDeserializationContext ctxt, + JavaType rootType, CollectionDeserializer deser, + Object valueToUpdate, List elementTypeList) + throws IOException + { + PropertyName expRootName = _config.findRootName(rootType); + String expSimpleName = expRootName.getSimpleName(); + if (p.currentToken() != JsonToken.START_OBJECT) { + ctxt.reportWrongTokenException(rootType, JsonToken.START_OBJECT, + "Current token not START_OBJECT (needed to unwrap root name %s), but %s", + ClassUtil.name(expSimpleName), p.currentToken()); + } + if (p.nextToken() != JsonToken.FIELD_NAME) { + ctxt.reportWrongTokenException(rootType, JsonToken.FIELD_NAME, + "Current token not FIELD_NAME (to contain expected root name %s), but %s", + ClassUtil.name(expSimpleName), p.currentToken()); + } + String actualName = p.currentName(); + if (!expSimpleName.equals(actualName)) { + ctxt.reportPropertyInputMismatch(rootType, actualName, + "Root name (%s) does not match expected (%s) for type %s", + ClassUtil.name(actualName), ClassUtil.name(expSimpleName), + ClassUtil.getTypeDescription(rootType)); + } + p.nextToken(); + final List result; + if (valueToUpdate == null) { + result = deserializeList(deser, p, ctxt, elementTypeList); + } else { + result = deserializeList(deser, p, ctxt, (List) valueToUpdate, elementTypeList); + } + if (p.nextToken() != JsonToken.END_OBJECT) { + ctxt.reportWrongTokenException(rootType, JsonToken.END_OBJECT, + "Current token not END_OBJECT (to match wrapper object with root name %s), but %s", + ClassUtil.name(expSimpleName), p.currentToken()); + } + return result; + } + + @SuppressWarnings("unchecked") + protected List deserializeList(CollectionDeserializer deser, JsonParser p, + DeserializationContext ctxt, + List elemenTypeList) + throws IOException + { + if (p.isExpectedStartArrayToken()) { + List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt); + return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList); + } + if (p.hasToken(JsonToken.VALUE_STRING)) { + List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt); + return _deserializeFromStringWithElementTypeList(deser, p, ctxt, + p.getText(), result, elemenTypeList); + } + List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt); + return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList); + } + + protected List deserializeList(CollectionDeserializer deser, JsonParser p, + DeserializationContext ctxt, List result, + List elemenTypeList) + throws IOException + { + if (p.isExpectedStartArrayToken()) { + return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList); + } + return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList); + } + + protected List _deserializeFromArrayWithElementTypeList(JsonParser p, + DeserializationContext ctxt, + List result, List elemenTypeList) + throws IOException + { + p.setCurrentValue(result); + + JsonDeserializer valueDes = null; + JsonToken t; + int idx = -1; + while ((t = p.nextToken()) != JsonToken.END_ARRAY) { + try { + idx++; + valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(idx), null); + Object value; + if (t == JsonToken.VALUE_NULL) { + value = null; + } else { + value = valueDes.deserialize(p, ctxt); + } + result.add(value); + } catch (Exception e) { + boolean wrap = (ctxt == null) || ctxt.isEnabled(DeserializationFeature.WRAP_EXCEPTIONS); + if (!wrap) { + ClassUtil.throwIfRTE(e); + } + throw JsonMappingException.wrapWithPath(e, result, result.size()); + } + } + return result; + } + + @SuppressWarnings("unchecked") + protected List _deserializeFromStringWithElementTypeList(CollectionDeserializer deser, + JsonParser p, DeserializationContext ctxt, + String value, List result, List elemenTypeList) + throws IOException + { + final Class rawTargetType = deser.handledType(); + if (value.isEmpty()) { + CoercionAction act = ctxt.findCoercionAction(deser.logicalType(), rawTargetType, + CoercionInputShape.EmptyString); + if (act != null && act != CoercionAction.Fail) { + return (List) deser.deserializeFromEmptyString( + p, ctxt, act, rawTargetType, "empty String (\"\")"); + } + } + else if (deser.isBlank(value)) { + final CoercionAction act = ctxt.findCoercionFromBlankString(deser.logicalType(), rawTargetType, + CoercionAction.Fail); + if (act != CoercionAction.Fail) { + return (List) deser.deserializeFromEmptyString( + p, ctxt, act, rawTargetType, "blank String (all whitespace)"); + } + } + return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList); + } + + @SuppressWarnings("unchecked") + protected final List handleNonArrayWithElementTypeList(CollectionDeserializer deser, + JsonParser p, DeserializationContext ctxt, + List result, List elemenTypeList) + throws IOException + { + boolean canWrap = (deser.getUnwrapSingle() == Boolean.TRUE) || + ((deser.getUnwrapSingle() == null) && + ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY)); + if (!canWrap) { + return (List) ctxt.handleUnexpectedToken(deser.getContainerType(), p); + } + JsonDeserializer valueDes = null; + valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(0), null); + + Object value; + try { + if (p.hasToken(JsonToken.VALUE_NULL)) { + value = null; + } else { + value = valueDes.deserialize(p, ctxt); + } + } catch (Exception e) { + boolean wrap = ctxt.isEnabled(DeserializationFeature.WRAP_EXCEPTIONS); + if (!wrap) { + ClassUtil.throwIfRTE(e); + } + throw JsonMappingException.wrapWithPath(e, Object.class, result.size()); + } + result.add(value); + return result; + } + /** * Convenience method that is equivalent to: *
      @@ -2208,7 +2411,7 @@ protected  MappingIterator _bindAndReadValues(JsonParser p) throws IOExcep
           }
       
           /**
      -     * Consider filter when creating JsonParser.  
      +     * Consider filter when creating JsonParser.
            */
           protected JsonParser _considerFilter(final JsonParser p, boolean multiValue) {
               // 26-Mar-2016, tatu: Need to allow multiple-matches at least if we have
      @@ -2259,7 +2462,7 @@ protected Object _detectBindAndClose(DataFormatReaders.Match match, boolean forc
                   _reportUnkownFormat(_dataFormatReaders, match);
               }
               JsonParser p = match.createParserWithMatch();
      -        // One more thing: we Own the input stream now; and while it's 
      +        // One more thing: we Own the input stream now; and while it's
               // not super clean way to do it, we must ensure closure so:
               if (forceClosing) {
                   p.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
      @@ -2275,7 +2478,7 @@ protected  MappingIterator _detectBindAndReadValues(DataFormatReaders.Matc
                   _reportUnkownFormat(_dataFormatReaders, match);
               }
               JsonParser p = match.createParserWithMatch();
      -        // One more thing: we Own the input stream now; and while it's 
      +        // One more thing: we Own the input stream now; and while it's
               // not super clean way to do it, we must ensure closure so:
               if (forceClosing) {
                   p.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
      diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
      index 7f6d20dc91..2fcbaa5b52 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/deser/DefaultDeserializationContext.java
      @@ -315,41 +315,20 @@ public abstract DefaultDeserializationContext createDummyInstance(
           public Object readRootValue(JsonParser p, JavaType valueType,
                   JsonDeserializer deser, Object valueToUpdate)
               throws IOException
      -    {
      -        return readRootValueWithElementTypeList(p, valueType, deser, valueToUpdate, null);
      -    }
      -
      -    public Object readRootValueWithElementTypeList(JsonParser p, JavaType valueType,
      -            JsonDeserializer deser, Object valueToUpdate, List elemenTypeList)
      -        throws IOException
           {
               if (_config.useRootWrapping()) {
      -            return _unwrapAndDeserializeWithElementTypeList(p, valueType, deser, valueToUpdate, elemenTypeList);
      +            return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate);
               }
               if (valueToUpdate == null) {
      -            if (null == elemenTypeList) {
      -                return deser.deserialize(p, this);
      -            }
      -            return deser.deserializeList(p, this, elemenTypeList);
      -        }
      -        if (null == elemenTypeList) {
      -            return deser.deserialize(p, this, valueToUpdate);
      +            return deser.deserialize(p, this);
               }
      -        return deser.deserializeList(p, this, valueToUpdate, elemenTypeList);
      +        return deser.deserialize(p, this, valueToUpdate);
           }
       
           protected Object _unwrapAndDeserialize(JsonParser p,
                   JavaType rootType, JsonDeserializer deser,
                   Object valueToUpdate)
               throws IOException
      -    {
      -        return _unwrapAndDeserializeWithElementTypeList(p, rootType, deser, valueToUpdate, null);
      -    }
      -
      -    protected Object _unwrapAndDeserializeWithElementTypeList(JsonParser p,
      -            JavaType rootType, JsonDeserializer deser,
      -            Object valueToUpdate, List elemenTypeList)
      -        throws IOException
           {
               PropertyName expRootName = _config.findRootName(rootType);
               // 12-Jun-2015, tatu: Should try to support namespaces etc but...
      @@ -374,17 +353,9 @@ protected Object _unwrapAndDeserializeWithElementTypeList(JsonParser p,
               p.nextToken();
               final Object result;
               if (valueToUpdate == null) {
      -            if (null == elemenTypeList) {
      -                result = deser.deserialize(p, this);
      -            } else {
      -                result = deser.deserializeList(p, this, elemenTypeList);
      -            }
      +            result = deser.deserialize(p, this);
               } else {
      -            if (null == elemenTypeList) {
      -                result = deser.deserialize(p, this, valueToUpdate);
      -            } else {
      -                result = deser.deserializeList(p, this, valueToUpdate, elemenTypeList);
      -            }
      +            result = deser.deserialize(p, this, valueToUpdate);
               }
               // and last, verify that we now get matching END_OBJECT
               if (p.nextToken() != JsonToken.END_OBJECT) {
      diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java
      index d0880a1a35..a27211b9eb 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ArrayBlockingQueueDeserializer.java
      @@ -90,26 +90,17 @@ protected Collection createDefaultInstance(DeserializationContext ctxt)
           protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt,
                   Collection result0)
               throws IOException
      -    {
      -        return _deserializeFromArrayWithElementTypeList(p, ctxt, result0, null);
      -    }
      -
      -    @Override
      -    protected Collection _deserializeFromArrayWithElementTypeList(JsonParser p,
      -            DeserializationContext ctxt,
      -            Collection result0, List elemenTypeList)
      -        throws IOException
           {
               if (result0 == null) { // usual case
                   result0 = new ArrayList<>();
               }
      -        result0 = super._deserializeFromArrayWithElementTypeList(p, ctxt, result0, elemenTypeList);
      +        result0 = super._deserializeFromArray(p, ctxt, result0);
               if (result0.isEmpty()) {
                   return new ArrayBlockingQueue<>(1, false);
               }
               return new ArrayBlockingQueue<>(result0.size(), false, result0);
           }
      -    
      +
           @Override
           public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException {
               // In future could check current token... for now this should be enough:
      diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      index ec509906bb..b6ef4042be 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      @@ -229,40 +229,27 @@ public ValueInstantiator getValueInstantiator() {
           /**********************************************************
            */
       
      -    @Override
      -    public Collection deserialize(JsonParser p, DeserializationContext ctxt)
      -        throws IOException
      -    {
      -        return deserializeList(p, ctxt, null);
      -    }
      -
           @SuppressWarnings("unchecked")
           @Override
      -    public Collection deserializeList(JsonParser p, DeserializationContext ctxt,
      -            List elemenTypeList)
      +    public Collection deserialize(JsonParser p, DeserializationContext ctxt)
               throws IOException
           {
               if (_delegateDeserializer != null) {
      -            if (null == elemenTypeList) {
      -                return (Collection) _valueInstantiator.createUsingDelegate(ctxt,
      -                        _delegateDeserializer.deserialize(p, ctxt));
      -            }
                   return (Collection) _valueInstantiator.createUsingDelegate(ctxt,
      -                    _delegateDeserializer.deserializeList(p, ctxt, elemenTypeList));
      +                    _delegateDeserializer.deserialize(p, ctxt));
               }
               // 16-May-2020, tatu: As per [dataformats-text#199] need to first check for
               //   possible Array-coercion and only after that String coercion
               if (p.isExpectedStartArrayToken()) {
      -            return _deserializeFromArrayWithElementTypeList(p, ctxt,
      -                    createDefaultInstance(ctxt), elemenTypeList);
      +            return _deserializeFromArray(p, ctxt, createDefaultInstance(ctxt));
               }
               // Empty String may be ok; bit tricky to check, however, since
               // there is also possibility of "auto-wrapping" of single-element arrays.
               // Hence we only accept empty String here.
               if (p.hasToken(JsonToken.VALUE_STRING)) {
      -            return _deserializeFromStringWithElementTypeList(p, ctxt, p.getText(), elemenTypeList);
      +            return _deserializeFromString(p, ctxt, p.getText());
               }
      -        return handleNonArrayWithElementTypeList(p, ctxt, createDefaultInstance(ctxt), elemenTypeList);
      +        return handleNonArray(p, ctxt, createDefaultInstance(ctxt));
           }
       
           /**
      @@ -279,20 +266,12 @@ protected Collection createDefaultInstance(DeserializationContext ctxt)
           public Collection deserialize(JsonParser p, DeserializationContext ctxt,
                   Collection result)
               throws IOException
      -    {
      -        return deserializeList(p, ctxt, result, null);
      -    }
      -
      -    @Override
      -    public Collection deserializeList(JsonParser p, DeserializationContext ctxt,
      -            Collection result, List elemenTypeList)
      -        throws IOException
           {
               // Ok: must point to START_ARRAY (or equivalent)
               if (p.isExpectedStartArrayToken()) {
      -            return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList);
      +            return _deserializeFromArray(p, ctxt, result);
               }
      -        return handleNonArrayWithElementTypeList(p, ctxt, result, elemenTypeList);
      +        return handleNonArray(p, ctxt, result);
           }
       
           @Override
      @@ -309,18 +288,10 @@ public Object deserializeWithType(JsonParser p, DeserializationContext ctxt,
            *
            * @since 2.12
            */
      +    @SuppressWarnings("unchecked")
           protected Collection _deserializeFromString(JsonParser p, DeserializationContext ctxt,
                   String value)
               throws IOException
      -    {
      -        return _deserializeFromStringWithElementTypeList(p, ctxt, value, null);
      -    }
      -
      -    @SuppressWarnings("unchecked")
      -    protected Collection _deserializeFromStringWithElementTypeList(JsonParser p,
      -            DeserializationContext ctxt,
      -            String value, List elemenTypeList)
      -        throws IOException
           {
               final Class rawTargetType = handledType();
       
      @@ -356,7 +327,7 @@ else if (_isBlank(value)) {
                   // note: `CoercionAction.Fail` falls through because we may need to allow
                   // `ACCEPT_SINGLE_VALUE_AS_ARRAY` handling later on
               }
      -        return handleNonArrayWithElementTypeList(p, ctxt, createDefaultInstance(ctxt), elemenTypeList);
      +        return handleNonArray(p, ctxt, createDefaultInstance(ctxt));
           }
       
           /**
      @@ -365,48 +336,29 @@ else if (_isBlank(value)) {
           protected Collection _deserializeFromArray(JsonParser p, DeserializationContext ctxt,
                   Collection result)
               throws IOException
      -    {
      -        return _deserializeFromArrayWithElementTypeList(p, ctxt, result, null);
      -    }
      -    
      -    protected Collection _deserializeFromArrayWithElementTypeList(JsonParser p,
      -            DeserializationContext ctxt,
      -            Collection result, List elemenTypeList)
      -        throws IOException
           {
               // [databind#631]: Assign current value, to be accessible by custom serializers
               p.setCurrentValue(result);
       
      -        JsonDeserializer valueDes = null;
      -        if (null == elemenTypeList) {
      -            valueDes = _valueDeserializer;
      -            // Let's offline handling of values with Object Ids (simplifies code here)
      -            if (valueDes.getObjectIdReader() != null) {
      -                return _deserializeWithObjectId(p, ctxt, result);
      -            }
      +        JsonDeserializer valueDes = _valueDeserializer;
      +        // Let's offline handling of values with Object Ids (simplifies code here)
      +        if (valueDes.getObjectIdReader() != null) {
      +            return _deserializeWithObjectId(p, ctxt, result);
               }
      -
               final TypeDeserializer typeDeser = _valueTypeDeserializer;
               JsonToken t;
      -        int idx = -1;
               while ((t = p.nextToken()) != JsonToken.END_ARRAY) {
                   try {
      -                idx++;
                       Object value;
                       if (t == JsonToken.VALUE_NULL) {
                           if (_skipNullValues) {
                               continue;
                           }
                           value = _nullProvider.getNullValue(ctxt);
      +                } else if (typeDeser == null) {
      +                    value = valueDes.deserialize(p, ctxt);
                       } else {
      -                    if (null != elemenTypeList) {
      -                        valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(idx), null);
      -                    }
      -                    if (typeDeser == null) {
      -                        value = valueDes.deserialize(p, ctxt);
      -                    } else {
      -                        value = valueDes.deserializeWithType(p, ctxt, typeDeser);
      -                    }
      +                    value = valueDes.deserializeWithType(p, ctxt, typeDeser);
                       }
                       result.add(value);
       
      @@ -431,18 +383,10 @@ protected Collection _deserializeFromArrayWithElementTypeList(JsonParser
            * throw an exception, or try to handle value as if member of implicit
            * array, depending on configuration.
            */
      +    @SuppressWarnings("unchecked")
           protected final Collection handleNonArray(JsonParser p, DeserializationContext ctxt,
                   Collection result)
               throws IOException
      -    {
      -        return handleNonArrayWithElementTypeList(p, ctxt, result, null);
      -    }
      -
      -    @SuppressWarnings("unchecked")
      -    protected final Collection handleNonArrayWithElementTypeList(JsonParser p,
      -            DeserializationContext ctxt,
      -            Collection result, List elemenTypeList)
      -        throws IOException
           {
               // Implicit arrays from single values?
               boolean canWrap = (_unwrapSingle == Boolean.TRUE) ||
      @@ -451,12 +395,7 @@ protected final Collection handleNonArrayWithElementTypeList(JsonParser
               if (!canWrap) {
                   return (Collection) ctxt.handleUnexpectedToken(_containerType, p);
               }
      -        JsonDeserializer valueDes = null;
      -        if (null == elemenTypeList) {
      -            valueDes = _valueDeserializer;
      -        } else {
      -            valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(0), null);
      -        }
      +        JsonDeserializer valueDes = _valueDeserializer;
               final TypeDeserializer typeDeser = _valueTypeDeserializer;
       
               Object value;
      @@ -588,6 +527,28 @@ public void resolveForwardReference(Object id, Object value) throws IOException
               }
           }
       
      +    public Object deserializeFromEmptyString(JsonParser p, DeserializationContext ctxt,
      +            CoercionAction act, Class rawTargetType, String desc) throws IOException
      +    {
      +        return _deserializeFromEmptyString(p, ctxt, act, rawTargetType, desc);
      +    }
      +
      +    public boolean isBlank(String text) {
      +        return _isBlank(text);
      +    }
      +
      +    public Boolean getUnwrapSingle() {
      +        return _unwrapSingle;
      +    }
      +
      +    public JavaType getContainerType() {
      +        return _containerType;
      +    }
      +
      +    public JsonDeserializer getDelegateDeserializer() {
      +        return _delegateDeserializer;
      +    }
      +
           /**
            * Helper class to maintain processing order of value. The resolved
            * object associated with {@link #_id} comes before the values in
      diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java
      index 6f88c58631..c465cf3068 100644
      --- a/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java
      +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectMapperTest.java
      @@ -1,19 +1,8 @@
       package com.fasterxml.jackson.databind;
       
      -import java.io.ByteArrayInputStream;
      -import java.io.ByteArrayOutputStream;
      -import java.io.DataInput;
      -import java.io.DataInputStream;
      -import java.io.DataOutput;
      -import java.io.DataOutputStream;
      -import java.io.IOException;
      -import java.math.BigDecimal;
      -import java.util.ArrayList;
      -import java.util.Arrays;
      -import java.util.HashSet;
      -import java.util.List;
      -import java.util.Map;
      -import java.util.TimeZone;
      +import com.fasterxml.jackson.databind.module.SimpleModule;
      +import java.io.*;
      +import java.util.*;
       
       import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
       import com.fasterxml.jackson.annotation.JsonInclude;
      @@ -21,20 +10,14 @@
       import com.fasterxml.jackson.annotation.JsonTypeInfo;
       import com.fasterxml.jackson.annotation.JsonTypeName;
       import com.fasterxml.jackson.annotation.Nulls;
      -import com.fasterxml.jackson.core.JsonFactory;
      -import com.fasterxml.jackson.core.JsonGenerator;
      -import com.fasterxml.jackson.core.JsonParser;
      -import com.fasterxml.jackson.core.JsonProcessingException;
      -import com.fasterxml.jackson.core.StreamReadFeature;
      -import com.fasterxml.jackson.core.StreamWriteFeature;
      +import com.fasterxml.jackson.core.*;
       import com.fasterxml.jackson.core.json.JsonWriteFeature;
       import com.fasterxml.jackson.core.util.MinimalPrettyPrinter;
      +
       import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
       import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
       import com.fasterxml.jackson.databind.json.JsonMapper;
      -import com.fasterxml.jackson.databind.module.SimpleModule;
      -import com.fasterxml.jackson.databind.node.JsonNodeFactory;
      -import com.fasterxml.jackson.databind.node.ObjectNode;
      +import com.fasterxml.jackson.databind.node.*;
       
       public class ObjectMapperTest extends BaseMapTest
       {
      @@ -561,19 +544,4 @@ public void testHasExplicitTimeZone() throws Exception
                   assertEquals(DEFAULT_TZ, w2.getConfig().getTimeZone());
               }
           }
      -
      -    public void testReadValueByItemTypes() throws JsonMappingException, JsonProcessingException {
      -        ObjectMapper mapper = new ObjectMapper();
      -        String content = "[1,2,3,null]";
      -        List elemenTypeList = new ArrayList<>();
      -        elemenTypeList.add(mapper.constructType(Integer.class));
      -        elemenTypeList.add(mapper.constructType(BigDecimal.class));
      -        elemenTypeList.add(mapper.constructType(Long.class));
      -        elemenTypeList.add(mapper.constructType(String.class));
      -        List objectList = mapper.readValue(content, elemenTypeList);
      -        assertEquals(new Integer(1), objectList.get(0));
      -        assertEquals(new BigDecimal("2"), objectList.get(1));
      -        assertEquals(new Long(3), objectList.get(2));
      -        assertEquals(null, objectList.get(3));
      -    }
       }
      diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      index 706d5189e4..7ec7571c97 100644
      --- a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      @@ -2,16 +2,18 @@
       
       import java.io.IOException;
       import java.io.StringWriter;
      +import java.math.BigDecimal;
       import java.util.*;
       
       import com.fasterxml.jackson.annotation.JsonCreator;
       import com.fasterxml.jackson.annotation.JsonProperty;
      -
      +import com.fasterxml.jackson.annotation.JsonTypeInfo;
       import com.fasterxml.jackson.core.*;
       import com.fasterxml.jackson.core.exc.StreamReadException;
       import com.fasterxml.jackson.core.json.JsonReadFeature;
      -
      +import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
       import com.fasterxml.jackson.databind.cfg.ContextAttributes;
      +import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
       import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
       import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
       import com.fasterxml.jackson.databind.exc.MismatchedInputException;
      @@ -414,7 +416,7 @@ public void testPointerWithArrays() throws Exception
           public static class Pojo1637 {
               public Set set1;
               public Set set2;
      -    }    
      +    }
       
           // [databind#2636]
           public void testCanPassResultToOverloadedMethod() throws Exception {
      @@ -532,4 +534,146 @@ private A(@JsonProperty("knownField") String knownField) {
                   this.knownField = knownField;
               }
           }
      +
      +    @SuppressWarnings("unchecked")
      +    public void testReaderForFixedElementTypes() throws IOException {
      +        List elementTypeList = new ArrayList<>();
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(Integer.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(BigDecimal.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(Long.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(String.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructParametricType(Generic.class, BigDecimal.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructCollectionType(List.class, Shape.class));
      +        String content = "[]";
      +        JsonParser p = MAPPER.createParser(content);
      +        List objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        p.close();
      +        assertEquals(0, objectList.size());
      +        content = "[null,null,null,null,null]";
      +        p = MAPPER.createParser(content);
      +        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        p.close();
      +        assertEquals(5, objectList.size());
      +        content = "[1,2,3,null,{\"s\":1.23},"
      +                + "[{\"@class\":\"" + getClass().getCanonicalName() + "$Circle\","
      +                + "\"radius\":4},"
      +                + "{\"@class\":\"" + getClass().getCanonicalName() + "$Rectangle\","
      +                + "\"width\":5,\"height\":6}]]";
      +        p = MAPPER.createParser(content);
      +        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        p.close();
      +        assertEquals(new Integer(1), objectList.get(0));
      +        assertEquals(new BigDecimal("2"), objectList.get(1));
      +        assertEquals(new Long(3), objectList.get(2));
      +        assertEquals(null, objectList.get(3));
      +        assertEquals(new BigDecimal("1.23"), ((Generic) objectList.get(4)).getT());
      +        assertEquals(4, ((Circle) ((List) objectList.get(5)).get(0)).getRadius());
      +        assertEquals(5, ((Rectangle) ((List) objectList.get(5)).get(1)).getWidth());
      +        assertEquals(6, ((Rectangle) ((List) objectList.get(5)).get(1)).getHeight());
      +        elementTypeList.clear();
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(Integer.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(BigDecimal.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(Long.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(String.class));
      +        content = "[1,2,3,null]";
      +        p = MAPPER.createParser(content);
      +        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        p.close();
      +        assertEquals(new Integer(1), objectList.get(0));
      +        assertEquals(new BigDecimal("2"), objectList.get(1));
      +        assertEquals(new Long(3), objectList.get(2));
      +    }
      +
      +    @JsonDeserialize(using = Generic.CustomerDeserializer.class)
      +    private static class Generic {
      +        private T t;
      +
      +        public T getT() {
      +            return t;
      +        }
      +
      +        public void setT(T t) {
      +            this.t = t;
      +        }
      +
      +        private static class CustomerDeserializer extends JsonDeserializer>
      +                implements ContextualDeserializer {
      +
      +            private Class tClazz;
      +
      +            @SuppressWarnings("unused")
      +            public CustomerDeserializer() {
      +            }
      +
      +            public CustomerDeserializer(Class tClazz) {
      +                this.tClazz = tClazz;
      +            }
      +
      +            @Override
      +            public Generic deserialize(JsonParser p, DeserializationContext ctxt)
      +                    throws IOException, JacksonException {
      +                JsonNode node = ctxt.readTree(p).findValue("s");
      +                Generic g = new Generic<>();
      +                Object t = ((ObjectMapper) p.getCodec()).convertValue(node, this.tClazz);
      +                g.setT(t);
      +                return g;
      +            }
      +
      +            @Override
      +            public JsonDeserializer createContextual(DeserializationContext ctxt, BeanProperty property)
      +                    throws JsonMappingException {
      +                JavaType currentType = null;
      +                if (property == null) {
      +                    // current type is root type.
      +                    currentType = ctxt.getContextualType();
      +                } else {
      +                    // current type is wrapped in other type.
      +                    currentType = property.getType();
      +                }
      +                Class tClazz = currentType.getBindings().getBoundType(0).getRawClass();
      +                return new CustomerDeserializer(tClazz);
      +            }
      +        }
      +    }
      +
      +    @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
      +    private static class Shape {
      +
      +    }
      +
      +    private static class Circle extends Shape {
      +        private int radius;
      +
      +        public int getRadius() {
      +            return radius;
      +        }
      +
      +        @SuppressWarnings("unused")
      +        public void setRadius(int radius) {
      +            this.radius = radius;
      +        }
      +    }
      +
      +    private static class Rectangle extends Shape {
      +        private int width;
      +        private int height;
      +
      +        public int getWidth() {
      +            return width;
      +        }
      +
      +        @SuppressWarnings("unused")
      +        public void setWidth(int width) {
      +            this.width = width;
      +        }
      +
      +        public int getHeight() {
      +            return height;
      +        }
      +
      +        @SuppressWarnings("unused")
      +        public void setHeight(int height) {
      +            this.height = height;
      +        }
      +    }
       }
      
      From 769f0551bf34d2183c132d05fa7d993f10bb161a Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Sun, 11 Sep 2022 13:41:43 +0800
      Subject: [PATCH 05/10] initialize list type at object reader construction
      
      ---
       .../jackson/databind/ObjectReader.java        | 19 +++++++++++++++----
       1 file changed, 15 insertions(+), 4 deletions(-)
      
      diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      index ab28bb146d..10e5248afb 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      @@ -78,6 +78,8 @@ public class ObjectReader
            */
           protected final boolean _unwrapRoot;
       
      +    protected final JavaType _listType;
      +
           /**
            * Filter to be consider for JsonParser.
            * Default value to be null as filter not considered.
      @@ -196,6 +198,8 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
               _rootDeserializer = _prefetchRootDeserializer(valueType);
               _dataFormatReaders = null;
               _filter = null;
      +
      +        _listType = _config.constructType(List.class);
           }
           
           /**
      @@ -220,6 +224,8 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
               _unwrapRoot = config.useRootWrapping();
               _dataFormatReaders = dataFormatReaders;
               _filter = base._filter;
      +
      +        _listType = _config.constructType(List.class);
           }
       
           /**
      @@ -241,6 +247,8 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
               _unwrapRoot = config.useRootWrapping();
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
      +
      +        _listType = _config.constructType(List.class);
           }
           
           protected ObjectReader(ObjectReader base, JsonFactory f)
      @@ -261,6 +269,8 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
               _unwrapRoot = base._unwrapRoot;
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
      +
      +        _listType = _config.constructType(List.class);
           }
           
           protected ObjectReader(ObjectReader base, TokenFilter filter) {
      @@ -276,6 +286,8 @@ protected ObjectReader(ObjectReader base, TokenFilter filter) {
               _unwrapRoot = base._unwrapRoot;
               _dataFormatReaders = base._dataFormatReaders;
               _filter = filter;
      +
      +        _listType = _config.constructType(List.class);
           }
           
           /**
      @@ -1298,9 +1310,8 @@ public  T readValue(JsonParser p, JavaType valueType) throws IOException {
       
           @SuppressWarnings("unchecked")
           public List readValue(JsonParser p, List elementTypeList) throws IOException {
      -        JavaType valueType = _config.constructType(List.class);
      -        if (!valueType.equals(_valueType)) {
      -            return forType(valueType).readValue(p, elementTypeList);
      +        if (!_listType.equals(_valueType)) {
      +            return forType(List.class).readValue(p, elementTypeList);
               }
               _assertNotNull("p", p);
               _assertNotNull("elementTypeList", elementTypeList);
      @@ -1320,7 +1331,7 @@ public List readValue(JsonParser p, List elementTypeList) thro
                           (CollectionDeserializer) ((JsonDeserializer) _findRootDeserializer(ctxt));
                   if (_config.useRootWrapping()) {
                       return _unwrapAndDeserializeWithElementTypeList(
      -                        p, ctxt, valueType, deser, _valueToUpdate, elementTypeList);
      +                        p, ctxt, _valueType, deser, _valueToUpdate, elementTypeList);
                   }
                   if (_valueToUpdate == null) {
                       return deserializeList(deser, p, ctxt, elementTypeList);
      
      From 26a58266e4ea3916ed6abf3fa0297dd2eab0af58 Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Sun, 11 Sep 2022 14:23:40 +0800
      Subject: [PATCH 06/10] fixed list object reader judging condition
      
      ---
       .../fasterxml/jackson/databind/ObjectReader.java | 16 ++++++++--------
       .../jackson/databind/ObjectReaderTest.java       | 10 ++++++----
       2 files changed, 14 insertions(+), 12 deletions(-)
      
      diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      index 10e5248afb..3cfb6cb1ad 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      @@ -78,8 +78,6 @@ public class ObjectReader
            */
           protected final boolean _unwrapRoot;
       
      -    protected final JavaType _listType;
      -
           /**
            * Filter to be consider for JsonParser.
            * Default value to be null as filter not considered.
      @@ -147,6 +145,8 @@ public class ObjectReader
            */
           protected final DataFormatReaders _dataFormatReaders;
       
      +    protected final boolean _isListObjectReader;
      +
           /*
           /**********************************************************
           /* Caching
      @@ -199,7 +199,7 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
               _dataFormatReaders = null;
               _filter = null;
       
      -        _listType = _config.constructType(List.class);
      +        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      @@ -225,7 +225,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
               _dataFormatReaders = dataFormatReaders;
               _filter = base._filter;
       
      -        _listType = _config.constructType(List.class);
      +        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
           }
       
           /**
      @@ -248,7 +248,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
       
      -        _listType = _config.constructType(List.class);
      +        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, JsonFactory f)
      @@ -270,7 +270,7 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
       
      -        _listType = _config.constructType(List.class);
      +        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, TokenFilter filter) {
      @@ -287,7 +287,7 @@ protected ObjectReader(ObjectReader base, TokenFilter filter) {
               _dataFormatReaders = base._dataFormatReaders;
               _filter = filter;
       
      -        _listType = _config.constructType(List.class);
      +        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      @@ -1310,7 +1310,7 @@ public  T readValue(JsonParser p, JavaType valueType) throws IOException {
       
           @SuppressWarnings("unchecked")
           public List readValue(JsonParser p, List elementTypeList) throws IOException {
      -        if (!_listType.equals(_valueType)) {
      +        if (!_isListObjectReader) {
                   return forType(List.class).readValue(p, elementTypeList);
               }
               _assertNotNull("p", p);
      diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      index 7ec7571c97..e4ca93033a 100644
      --- a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      @@ -546,12 +546,14 @@ public void testReaderForFixedElementTypes() throws IOException {
               elementTypeList.add(MAPPER.getTypeFactory().constructCollectionType(List.class, Shape.class));
               String content = "[]";
               JsonParser p = MAPPER.createParser(content);
      -        List objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        ObjectReader listObjectReader = MAPPER.readerFor(List.class);
      +        List objectList = listObjectReader.readValue(p, elementTypeList);
               p.close();
               assertEquals(0, objectList.size());
               content = "[null,null,null,null,null]";
               p = MAPPER.createParser(content);
      -        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        listObjectReader = MAPPER.readerFor(ArrayList.class);
      +        objectList = listObjectReader.readValue(p, elementTypeList);
               p.close();
               assertEquals(5, objectList.size());
               content = "[1,2,3,null,{\"s\":1.23},"
      @@ -560,7 +562,7 @@ public void testReaderForFixedElementTypes() throws IOException {
                       + "{\"@class\":\"" + getClass().getCanonicalName() + "$Rectangle\","
                       + "\"width\":5,\"height\":6}]]";
               p = MAPPER.createParser(content);
      -        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        objectList = listObjectReader.readValue(p, elementTypeList);
               p.close();
               assertEquals(new Integer(1), objectList.get(0));
               assertEquals(new BigDecimal("2"), objectList.get(1));
      @@ -577,7 +579,7 @@ public void testReaderForFixedElementTypes() throws IOException {
               elementTypeList.add(MAPPER.getTypeFactory().constructType(String.class));
               content = "[1,2,3,null]";
               p = MAPPER.createParser(content);
      -        objectList = MAPPER.readerFor(List.class).readValue(p, elementTypeList);
      +        objectList = listObjectReader.readValue(p, elementTypeList);
               p.close();
               assertEquals(new Integer(1), objectList.get(0));
               assertEquals(new BigDecimal("2"), objectList.get(1));
      
      From 732cd00b2cbeef53bae745bb9454eddebe54a371 Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Sun, 11 Sep 2022 16:39:58 +0800
      Subject: [PATCH 07/10] disable non array handler of fixed element types
      
      ---
       .../jackson/databind/ObjectReader.java        | 81 ++-----------------
       .../deser/std/CollectionDeserializer.java     | 22 -----
       2 files changed, 6 insertions(+), 97 deletions(-)
      
      diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      index 3cfb6cb1ad..e63403eb05 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      @@ -13,8 +13,6 @@
       import com.fasterxml.jackson.core.filter.TokenFilter.Inclusion;
       import com.fasterxml.jackson.core.type.ResolvedType;
       import com.fasterxml.jackson.core.type.TypeReference;
      -import com.fasterxml.jackson.databind.cfg.CoercionAction;
      -import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
       import com.fasterxml.jackson.databind.cfg.ContextAttributes;
       import com.fasterxml.jackson.databind.cfg.DatatypeFeature;
       import com.fasterxml.jackson.databind.deser.DataFormatReaders;
      @@ -1389,37 +1387,29 @@ protected List _unwrapAndDeserializeWithElementTypeList(JsonParser p,
       
           @SuppressWarnings("unchecked")
           protected List deserializeList(CollectionDeserializer deser, JsonParser p,
      -            DeserializationContext ctxt,
      -            List elemenTypeList)
      +            DeserializationContext ctxt, List elemenTypeList)
               throws IOException
           {
               if (p.isExpectedStartArrayToken()) {
                   List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt);
                   return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList);
               }
      -        if (p.hasToken(JsonToken.VALUE_STRING)) {
      -            List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt);
      -            return _deserializeFromStringWithElementTypeList(deser, p, ctxt,
      -                    p.getText(), result, elemenTypeList);
      -        }
      -        List result = (List) deser.getValueInstantiator().createUsingDefault(ctxt);
      -        return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList);
      +        return (List) ctxt.handleUnexpectedToken(deser.getValueType(), p);
           }
       
      +    @SuppressWarnings("unchecked")
           protected List deserializeList(CollectionDeserializer deser, JsonParser p,
      -            DeserializationContext ctxt, List result,
      -            List elemenTypeList)
      +            DeserializationContext ctxt, List result, List elemenTypeList)
               throws IOException
           {
               if (p.isExpectedStartArrayToken()) {
                   return _deserializeFromArrayWithElementTypeList(p, ctxt, result, elemenTypeList);
               }
      -        return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList);
      +        return (List) ctxt.handleUnexpectedToken(deser.getValueType(), p);
           }
       
           protected List _deserializeFromArrayWithElementTypeList(JsonParser p,
      -            DeserializationContext ctxt,
      -            List result, List elemenTypeList)
      +            DeserializationContext ctxt, List result, List elemenTypeList)
               throws IOException
           {
               p.setCurrentValue(result);
      @@ -1449,65 +1439,6 @@ protected List _deserializeFromArrayWithElementTypeList(JsonParser p,
               return result;
           }
       
      -    @SuppressWarnings("unchecked")
      -    protected List _deserializeFromStringWithElementTypeList(CollectionDeserializer deser,
      -            JsonParser p, DeserializationContext ctxt,
      -            String value, List result, List elemenTypeList)
      -        throws IOException
      -    {
      -        final Class rawTargetType = deser.handledType();
      -        if (value.isEmpty()) {
      -            CoercionAction act = ctxt.findCoercionAction(deser.logicalType(), rawTargetType,
      -                    CoercionInputShape.EmptyString);
      -            if (act != null && act != CoercionAction.Fail) {
      -                return (List) deser.deserializeFromEmptyString(
      -                        p, ctxt, act, rawTargetType, "empty String (\"\")");
      -            }
      -        }
      -        else if (deser.isBlank(value)) {
      -            final CoercionAction act = ctxt.findCoercionFromBlankString(deser.logicalType(), rawTargetType,
      -                    CoercionAction.Fail);
      -            if (act != CoercionAction.Fail) {
      -                return (List) deser.deserializeFromEmptyString(
      -                        p, ctxt, act, rawTargetType, "blank String (all whitespace)");
      -            }
      -        }
      -        return handleNonArrayWithElementTypeList(deser, p, ctxt, result, elemenTypeList);
      -    }
      -
      -    @SuppressWarnings("unchecked")
      -    protected final List handleNonArrayWithElementTypeList(CollectionDeserializer deser,
      -            JsonParser p, DeserializationContext ctxt,
      -            List result, List elemenTypeList)
      -        throws IOException
      -    {
      -        boolean canWrap = (deser.getUnwrapSingle() == Boolean.TRUE) ||
      -                ((deser.getUnwrapSingle() == null) &&
      -                        ctxt.isEnabled(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY));
      -        if (!canWrap) {
      -            return (List) ctxt.handleUnexpectedToken(deser.getContainerType(), p);
      -        }
      -        JsonDeserializer valueDes = null;
      -        valueDes = ctxt.findContextualValueDeserializer(elemenTypeList.get(0), null);
      -
      -        Object value;
      -        try {
      -            if (p.hasToken(JsonToken.VALUE_NULL)) {
      -                value = null;
      -            } else {
      -                value = valueDes.deserialize(p, ctxt);
      -            }
      -        } catch (Exception e) {
      -            boolean wrap = ctxt.isEnabled(DeserializationFeature.WRAP_EXCEPTIONS);
      -            if (!wrap) {
      -                ClassUtil.throwIfRTE(e);
      -            }
      -            throw JsonMappingException.wrapWithPath(e, Object.class, result.size());
      -        }
      -        result.add(value);
      -        return result;
      -    }
      -
           /**
            * Convenience method that is equivalent to:
            *
      diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      index b6ef4042be..42a0f54f6c 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java
      @@ -527,28 +527,6 @@ public void resolveForwardReference(Object id, Object value) throws IOException
               }
           }
       
      -    public Object deserializeFromEmptyString(JsonParser p, DeserializationContext ctxt,
      -            CoercionAction act, Class rawTargetType, String desc) throws IOException
      -    {
      -        return _deserializeFromEmptyString(p, ctxt, act, rawTargetType, desc);
      -    }
      -
      -    public boolean isBlank(String text) {
      -        return _isBlank(text);
      -    }
      -
      -    public Boolean getUnwrapSingle() {
      -        return _unwrapSingle;
      -    }
      -
      -    public JavaType getContainerType() {
      -        return _containerType;
      -    }
      -
      -    public JsonDeserializer getDelegateDeserializer() {
      -        return _delegateDeserializer;
      -    }
      -
           /**
            * Helper class to maintain processing order of value. The resolved
            * object associated with {@link #_id} comes before the values in
      
      From ab6e142709ace9bf1c042abcddf79ee1969da772 Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Sun, 11 Sep 2022 17:01:18 +0800
      Subject: [PATCH 08/10] fix _isListObjectReader
      
      ---
       .../com/fasterxml/jackson/databind/ObjectReader.java   | 10 +++++-----
       1 file changed, 5 insertions(+), 5 deletions(-)
      
      diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      index e63403eb05..65888bb679 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      @@ -197,7 +197,7 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
               _dataFormatReaders = null;
               _filter = null;
       
      -        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
      +        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      @@ -223,7 +223,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
               _dataFormatReaders = dataFormatReaders;
               _filter = base._filter;
       
      -        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
      +        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
       
           /**
      @@ -246,7 +246,7 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
       
      -        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
      +        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, JsonFactory f)
      @@ -268,7 +268,7 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
       
      -        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
      +        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, TokenFilter filter) {
      @@ -285,7 +285,7 @@ protected ObjectReader(ObjectReader base, TokenFilter filter) {
               _dataFormatReaders = base._dataFormatReaders;
               _filter = filter;
       
      -        _isListObjectReader = List.class.isAssignableFrom(_valueType.getRawClass());
      +        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      
      From 2fedde6fd6ef2bda10c4888286cc6970634cdaaf Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Mon, 12 Sep 2022 02:53:01 +0800
      Subject: [PATCH 09/10] optimize readValue
      
      ---
       .../fasterxml/jackson/databind/ObjectReader.java   | 14 +-------------
       1 file changed, 1 insertion(+), 13 deletions(-)
      
      diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      index 65888bb679..bfd29fa486 100644
      --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java
      @@ -143,8 +143,6 @@ public class ObjectReader
            */
           protected final DataFormatReaders _dataFormatReaders;
       
      -    protected final boolean _isListObjectReader;
      -
           /*
           /**********************************************************
           /* Caching
      @@ -196,8 +194,6 @@ protected ObjectReader(ObjectMapper mapper, DeserializationConfig config,
               _rootDeserializer = _prefetchRootDeserializer(valueType);
               _dataFormatReaders = null;
               _filter = null;
      -
      -        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      @@ -222,8 +218,6 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config,
               _unwrapRoot = config.useRootWrapping();
               _dataFormatReaders = dataFormatReaders;
               _filter = base._filter;
      -
      -        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
       
           /**
      @@ -245,8 +239,6 @@ protected ObjectReader(ObjectReader base, DeserializationConfig config)
               _unwrapRoot = config.useRootWrapping();
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
      -
      -        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, JsonFactory f)
      @@ -267,8 +259,6 @@ protected ObjectReader(ObjectReader base, JsonFactory f)
               _unwrapRoot = base._unwrapRoot;
               _dataFormatReaders = base._dataFormatReaders;
               _filter = base._filter;
      -
      -        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           protected ObjectReader(ObjectReader base, TokenFilter filter) {
      @@ -284,8 +274,6 @@ protected ObjectReader(ObjectReader base, TokenFilter filter) {
               _unwrapRoot = base._unwrapRoot;
               _dataFormatReaders = base._dataFormatReaders;
               _filter = filter;
      -
      -        _isListObjectReader = _valueType != null && List.class.isAssignableFrom(_valueType.getRawClass());
           }
           
           /**
      @@ -1308,7 +1296,7 @@ public  T readValue(JsonParser p, JavaType valueType) throws IOException {
       
           @SuppressWarnings("unchecked")
           public List readValue(JsonParser p, List elementTypeList) throws IOException {
      -        if (!_isListObjectReader) {
      +        if (_valueType == null || !List.class.isAssignableFrom(_valueType.getRawClass())) {
                   return forType(List.class).readValue(p, elementTypeList);
               }
               _assertNotNull("p", p);
      
      From 599fac3a9ebde1eb8f34c5fd1040c2b974aad63e Mon Sep 17 00:00:00 2001
      From: zrlw 
      Date: Mon, 12 Sep 2022 10:02:55 +0800
      Subject: [PATCH 10/10] add databind#735 testcase
      
      ---
       .../jackson/databind/ObjectReaderTest.java    | 48 ++++++++++++++++++-
       1 file changed, 47 insertions(+), 1 deletion(-)
      
      diff --git a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      index e4ca93033a..26866e41c4 100644
      --- a/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      +++ b/src/test/java/com/fasterxml/jackson/databind/ObjectReaderTest.java
      @@ -15,6 +15,7 @@
       import com.fasterxml.jackson.databind.cfg.ContextAttributes;
       import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
       import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler;
      +import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
       import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
       import com.fasterxml.jackson.databind.exc.MismatchedInputException;
       import com.fasterxml.jackson.databind.json.JsonMapper;
      @@ -544,6 +545,7 @@ public void testReaderForFixedElementTypes() throws IOException {
               elementTypeList.add(MAPPER.getTypeFactory().constructType(String.class));
               elementTypeList.add(MAPPER.getTypeFactory().constructParametricType(Generic.class, BigDecimal.class));
               elementTypeList.add(MAPPER.getTypeFactory().constructCollectionType(List.class, Shape.class));
      +        elementTypeList.add(MAPPER.getTypeFactory().constructType(TestBean.class));
               String content = "[]";
               JsonParser p = MAPPER.createParser(content);
               ObjectReader listObjectReader = MAPPER.readerFor(List.class);
      @@ -560,7 +562,8 @@ public void testReaderForFixedElementTypes() throws IOException {
                       + "[{\"@class\":\"" + getClass().getCanonicalName() + "$Circle\","
                       + "\"radius\":4},"
                       + "{\"@class\":\"" + getClass().getCanonicalName() + "$Rectangle\","
      -                + "\"width\":5,\"height\":6}]]";
      +                + "\"width\":5,\"height\":6}],"
      +                + "{\"map1\":{\"a\":1},\"map2\":{\"a\":1}}]";
               p = MAPPER.createParser(content);
               objectList = listObjectReader.readValue(p, elementTypeList);
               p.close();
      @@ -572,6 +575,8 @@ public void testReaderForFixedElementTypes() throws IOException {
               assertEquals(4, ((Circle) ((List) objectList.get(5)).get(0)).getRadius());
               assertEquals(5, ((Rectangle) ((List) objectList.get(5)).get(1)).getWidth());
               assertEquals(6, ((Rectangle) ((List) objectList.get(5)).get(1)).getHeight());
      +        assertEquals(100, ((TestBean) objectList.get(6)).getMap1().get("a").intValue());
      +        assertEquals(1, ((TestBean) objectList.get(6)).getMap2().get("a").intValue());
               elementTypeList.clear();
               elementTypeList.add(MAPPER.getTypeFactory().constructType(Integer.class));
               elementTypeList.add(MAPPER.getTypeFactory().constructType(BigDecimal.class));
      @@ -678,4 +683,45 @@ public void setHeight(int height) {
                   this.height = height;
               }
           }
      +
      +    @SuppressWarnings("unused")
      +    private static class TestBean {
      +
      +        @JsonProperty("map1")
      +        @JsonDeserialize(contentUsing = TestBeanCustomDeserializer.class)
      +        Map map1;
      +
      +        @JsonProperty("map2")
      +        Map map2;
      +
      +        public Map getMap1() {
      +            return map1;
      +        }
      +
      +        public void setMap1(Map map1) {
      +            this.map1 = map1;
      +        }
      +
      +        public Map getMap2() {
      +            return map2;
      +        }
      +
      +        public void setMap2(Map map2) {
      +            this.map2 = map2;
      +        }
      +    }
      +
      +    private static class TestBeanCustomDeserializer extends StdDeserializer {
      +        private static final long serialVersionUID = 1L;
      +
      +        public TestBeanCustomDeserializer() {
      +            super(Integer.class);
      +        }
      +
      +        @Override
      +        public Integer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
      +            Integer value = p.readValueAs(Integer.class);
      +            return value * 100;
      +        }
      +    }
       }