3232import com .fasterxml .jackson .annotation .JsonTypeInfo ;
3333import com .fasterxml .jackson .annotation .JsonTypeInfo .As ;
3434import com .fasterxml .jackson .core .JsonGenerator ;
35+ import com .fasterxml .jackson .core .JsonParser ;
36+ import com .fasterxml .jackson .core .JsonToken ;
3537import com .fasterxml .jackson .core .TreeNode ;
3638import com .fasterxml .jackson .databind .DeserializationConfig ;
3739import com .fasterxml .jackson .databind .JavaType ;
40+ import com .fasterxml .jackson .databind .JsonDeserializer ;
3841import com .fasterxml .jackson .databind .JsonNode ;
3942import com .fasterxml .jackson .databind .ObjectMapper ;
4043import com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping ;
4144import com .fasterxml .jackson .databind .SerializerProvider ;
45+ import com .fasterxml .jackson .databind .deser .BeanDeserializerFactory ;
46+ import com .fasterxml .jackson .databind .deser .DefaultDeserializationContext ;
47+ import com .fasterxml .jackson .databind .deser .std .JsonNodeDeserializer ;
4248import com .fasterxml .jackson .databind .jsontype .PolymorphicTypeValidator ;
4349import com .fasterxml .jackson .databind .jsontype .TypeDeserializer ;
4450import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
@@ -179,7 +185,7 @@ private static TypeResolver newTypeResolver(ObjectMapper mapper, @Nullable Strin
179185 Lazy <String > lazyTypeHintPropertyName = typeHintPropertyName != null ? Lazy .of (typeHintPropertyName )
180186 : newLazyTypeHintPropertyName (mapper , defaultTypingEnabled );
181187
182- return new TypeResolver (lazyTypeFactory , lazyTypeHintPropertyName );
188+ return new TypeResolver (mapper , lazyTypeFactory , lazyTypeHintPropertyName );
183189 }
184190
185191 private static Lazy <String > newLazyTypeHintPropertyName (ObjectMapper mapper , Lazy <Boolean > defaultTypingEnabled ) {
@@ -340,14 +346,13 @@ protected JavaType resolveType(byte[] source, Class<?> type) throws IOException
340346 */
341347 static class TypeResolver {
342348
343- // need a separate instance to bypass class hint checks
344- private final ObjectMapper mapper = new ObjectMapper ();
345-
349+ private final ObjectMapper mapper ;
346350 private final Supplier <TypeFactory > typeFactory ;
347351 private final Supplier <String > hintName ;
348352
349- TypeResolver (Supplier <TypeFactory > typeFactory , Supplier <String > hintName ) {
353+ TypeResolver (ObjectMapper mapper , Supplier <TypeFactory > typeFactory , Supplier <String > hintName ) {
350354
355+ this .mapper = mapper ;
351356 this .typeFactory = typeFactory ;
352357 this .hintName = hintName ;
353358 }
@@ -358,7 +363,7 @@ protected JavaType constructType(Class<?> type) {
358363
359364 protected JavaType resolveType (byte [] source , Class <?> type ) throws IOException {
360365
361- JsonNode root = mapper . readTree (source );
366+ JsonNode root = readTree (source );
362367 JsonNode jsonNode = root .get (hintName .get ());
363368
364369 if (jsonNode instanceof TextNode && jsonNode .asText () != null ) {
@@ -367,6 +372,42 @@ protected JavaType resolveType(byte[] source, Class<?> type) throws IOException
367372
368373 return constructType (type );
369374 }
375+
376+ /**
377+ * Lenient variant of ObjectMapper._readTreeAndClose using a strict {@link JsonNodeDeserializer}.
378+ *
379+ * @param source
380+ * @return
381+ * @throws IOException
382+ */
383+ private JsonNode readTree (byte [] source ) throws IOException {
384+
385+ JsonDeserializer <? extends JsonNode > deserializer = JsonNodeDeserializer .getDeserializer (JsonNode .class );
386+ DeserializationConfig cfg = mapper .getDeserializationConfig ();
387+
388+ try (JsonParser parser = mapper .createParser (source )) {
389+
390+ cfg .initialize (parser );
391+ JsonToken t = parser .currentToken ();
392+ if (t == null ) {
393+ t = parser .nextToken ();
394+ if (t == null ) {
395+ return cfg .getNodeFactory ().missingNode ();
396+ }
397+ }
398+
399+ /*
400+ * Hokey pokey! Oh my.
401+ */
402+ DefaultDeserializationContext ctxt = new DefaultDeserializationContext .Impl (BeanDeserializerFactory .instance )
403+ .createInstance (cfg , parser , mapper .getInjectableValues ());
404+ if (t == JsonToken .VALUE_NULL ) {
405+ return cfg .getNodeFactory ().nullNode ();
406+ } else {
407+ return deserializer .deserialize (parser , ctxt );
408+ }
409+ }
410+ }
370411 }
371412
372413 /**
0 commit comments