|
1 | 1 | package com.fasterxml.jackson.module.scala.deser
|
2 | 2 |
|
3 |
| -import com.fasterxml.jackson.core.JsonParser |
| 3 | +import com.fasterxml.jackson.core.{JsonToken, JsonParser} |
4 | 4 | import com.fasterxml.jackson.databind._
|
5 |
| -import com.fasterxml.jackson.databind.`type`.CollectionLikeType |
| 5 | +import com.fasterxml.jackson.databind.`type`.{ReferenceType, TypeFactory, CollectionLikeType} |
6 | 6 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer
|
7 | 7 | import com.fasterxml.jackson.databind.deser.{ContextualDeserializer, Deserializers}
|
8 | 8 | import com.fasterxml.jackson.databind.jsontype.TypeDeserializer
|
9 | 9 | import com.fasterxml.jackson.module.scala.modifiers.OptionTypeModifierModule
|
10 | 10 |
|
11 |
| -private class OptionDeserializer(elementType: JavaType, |
12 |
| - valueTypeDeser: Option[TypeDeserializer], |
13 |
| - beanProperty: Option[BeanProperty], |
14 |
| - elementDeser: Option[JsonDeserializer[_]]) |
15 |
| - extends StdDeserializer[Option[AnyRef]](classOf[Option[AnyRef]]) with ContextualDeserializer { |
16 |
| - |
17 |
| - override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[_] = { |
18 |
| - val typeDeser = valueTypeDeser.map(_.forProperty(property)) |
19 |
| - val deser: Option[JsonDeserializer[_]] = |
20 |
| - (for { |
21 |
| - p <- Option(property) |
22 |
| - m <- Option(p.getMember) |
23 |
| - deserDef <- Option(ctxt.getAnnotationIntrospector.findContentDeserializer(m)) |
24 |
| - } yield ctxt.deserializerInstance(m, deserDef)).orElse(elementDeser) |
25 |
| - val deser1: Option[JsonDeserializer[_]] = Option(findConvertingContentDeserializer(ctxt, property, deser.orNull)) |
26 |
| - val deser2: Option[JsonDeserializer[_]] = if (deser1.isEmpty) { |
27 |
| - if (hasContentTypeAnnotation(ctxt, property)) { |
28 |
| - Option(ctxt.findContextualValueDeserializer(elementType, property)) |
29 |
| - } else { |
30 |
| - deser1 |
31 |
| - } |
32 |
| - } else { |
33 |
| - Option(ctxt.handleSecondaryContextualization(deser1.get, property, elementType)) |
| 11 | +private class OptionDeserializer(fullType: JavaType, |
| 12 | + valueTypeDeserializer: Option[TypeDeserializer], |
| 13 | + valueDeserializer: Option[JsonDeserializer[AnyRef]], |
| 14 | + beanProperty: Option[BeanProperty] = None) |
| 15 | + extends StdDeserializer[Option[AnyRef]](fullType) with ContextualDeserializer { |
| 16 | + |
| 17 | + override def getValueType: JavaType = fullType |
| 18 | + |
| 19 | + override def getNullValue: Option[AnyRef] = None |
| 20 | + |
| 21 | + private[this] def withResolved(fullType: JavaType, |
| 22 | + typeDeser: Option[TypeDeserializer], |
| 23 | + valueDeser: Option[JsonDeserializer[_]], |
| 24 | + beanProperty: Option[BeanProperty]): OptionDeserializer = { |
| 25 | + if (fullType == this.fullType && |
| 26 | + typeDeser == this.valueTypeDeserializer && |
| 27 | + valueDeser == this.valueDeserializer && |
| 28 | + beanProperty == this.beanProperty) { |
| 29 | + return this |
34 | 30 | }
|
35 |
| - if (deser2 != elementDeser || property != beanProperty.orNull || valueTypeDeser != typeDeser) |
36 |
| - new OptionDeserializer(elementType, typeDeser, Option(property), deser2.asInstanceOf[Option[JsonDeserializer[AnyRef]]]) |
37 |
| - else this |
| 31 | + new OptionDeserializer(fullType, typeDeser, valueDeser.asInstanceOf[Option[JsonDeserializer[AnyRef]]], beanProperty) |
38 | 32 | }
|
39 | 33 |
|
40 |
| - def hasContentTypeAnnotation(ctxt: DeserializationContext, property: BeanProperty) = (for { |
41 |
| - p <- Option(property) |
42 |
| - intr <- Option(ctxt.getAnnotationIntrospector) |
43 |
| - } yield { |
44 |
| - intr.refineDeserializationType(ctxt.getConfig, p.getMember, p.getType) |
45 |
| - }).isDefined |
| 34 | + override def createContextual(ctxt: DeserializationContext, property: BeanProperty): JsonDeserializer[Option[AnyRef]] = { |
| 35 | + val typeDeser = valueTypeDeserializer.map(_.forProperty(property)) |
| 36 | + var deser = valueDeserializer |
| 37 | + var typ = fullType |
| 38 | + |
| 39 | + def refdType() = Option(typ.getContentType).getOrElse(TypeFactory.unknownType()) |
46 | 40 |
|
47 |
| - override def deserialize(jp: JsonParser, ctxt: DeserializationContext) = valueTypeDeser match { |
48 |
| - case Some(d) => deserializeWithType(jp, ctxt, d) |
49 |
| - case None => Option { |
50 |
| - elementDeser.map(_.deserialize(jp, ctxt)).getOrElse { |
51 |
| - ctxt.findContextualValueDeserializer(elementType, beanProperty.orNull).deserialize(jp, ctxt) |
| 41 | + if (deser.isEmpty) { |
| 42 | + if (property != null) { |
| 43 | + val intr = ctxt.getAnnotationIntrospector |
| 44 | + val member = property.getMember |
| 45 | + if (intr != null && member != null) { |
| 46 | + typ = intr.refineDeserializationType(ctxt.getConfig, member, typ) |
| 47 | + } |
| 48 | + deser = Option(ctxt.findContextualValueDeserializer(refdType(), property)) |
52 | 49 | }
|
53 |
| - }.asInstanceOf[Option[AnyRef]] |
| 50 | + } else { // otherwise directly assigned, probably not contextual yet: |
| 51 | + deser = Option(ctxt.handleSecondaryContextualization(deser.get, property, refdType()).asInstanceOf[JsonDeserializer[AnyRef]]) |
| 52 | + } |
| 53 | + |
| 54 | + withResolved(typ, typeDeser, deser, Option(property)) |
54 | 55 | }
|
55 | 56 |
|
56 |
| - override def deserializeWithType(jp: JsonParser, ctxt: DeserializationContext, typeDeserializer: TypeDeserializer) = Option { |
57 |
| - elementDeser.map(_.deserializeWithType(jp, ctxt, typeDeserializer)).getOrElse { |
58 |
| - ctxt.findContextualValueDeserializer(elementType, beanProperty.orNull).deserializeWithType(jp, ctxt, typeDeserializer) |
| 57 | + override def deserialize(p: JsonParser, ctxt: DeserializationContext): Option[AnyRef] = { |
| 58 | + val deser = valueDeserializer.getOrElse(ctxt.findContextualValueDeserializer(fullType.getContentType, beanProperty.orNull)) |
| 59 | + val refd: AnyRef = valueTypeDeserializer match { |
| 60 | + case None => deser.deserialize(p, ctxt) |
| 61 | + case Some(vtd) => deser.deserializeWithType(p, ctxt, vtd) |
59 | 62 | }
|
| 63 | + Option(refd) |
60 | 64 | }
|
61 | 65 |
|
62 |
| - override def getNullValue = None |
| 66 | + override def deserializeWithType(jp: JsonParser, ctxt: DeserializationContext, typeDeserializer: TypeDeserializer): Option[AnyRef] = { |
| 67 | + val t = jp.getCurrentToken |
| 68 | + if (t == JsonToken.VALUE_NULL) { |
| 69 | + getNullValue(ctxt) |
| 70 | + } else { |
| 71 | + typeDeserializer.deserializeTypedFromAny(jp, ctxt).asInstanceOf[Option[AnyRef]] |
| 72 | + } |
| 73 | + } |
63 | 74 | }
|
64 | 75 |
|
65 | 76 | private object OptionDeserializerResolver extends Deserializers.Base {
|
66 | 77 |
|
67 | 78 | private val OPTION = classOf[Option[AnyRef]]
|
68 | 79 |
|
69 |
| - override def findCollectionLikeDeserializer(theType: CollectionLikeType, |
70 |
| - config: DeserializationConfig, |
71 |
| - beanDesc: BeanDescription, |
72 |
| - elementTypeDeserializer: TypeDeserializer, |
73 |
| - elementValueDeserializer: JsonDeserializer[_]) = |
74 |
| - if (!OPTION.isAssignableFrom(theType.getRawClass)) null |
| 80 | + override def findReferenceDeserializer(refType: ReferenceType, |
| 81 | + config: DeserializationConfig, |
| 82 | + beanDesc: BeanDescription, |
| 83 | + contentTypeDeserializer: TypeDeserializer, |
| 84 | + contentDeserializer: JsonDeserializer[_]): JsonDeserializer[_] = { |
| 85 | + if (!OPTION.isAssignableFrom(refType.getRawClass)) null |
75 | 86 | else {
|
76 |
| - val elementType = theType.getContentType |
77 |
| - val typeDeser = Option(elementTypeDeserializer).orElse(Option(elementType.getTypeHandler.asInstanceOf[TypeDeserializer])) |
78 |
| - val valDeser: Option[JsonDeserializer[_]] = Option(elementValueDeserializer).orElse(Option(elementType.getValueHandler)) |
79 |
| - new OptionDeserializer(elementType, typeDeser, None, valDeser) |
| 87 | + val elementType = refType.getContentType |
| 88 | + val typeDeser = Option(contentTypeDeserializer).orElse(Option(elementType.getTypeHandler[TypeDeserializer])) |
| 89 | + val valDeser = Option(contentDeserializer).orElse(Option(elementType.getValueHandler)).asInstanceOf[Option[JsonDeserializer[AnyRef]]] |
| 90 | + new OptionDeserializer(refType, typeDeser, valDeser) |
80 | 91 | }
|
| 92 | + } |
81 | 93 | }
|
82 | 94 |
|
83 | 95 | trait OptionDeserializerModule extends OptionTypeModifierModule {
|
|
0 commit comments