11package com.fasterxml.jackson.module.kotlin
22
33import com.fasterxml.jackson.annotation.JsonProperty
4+ import com.fasterxml.jackson.annotation.OptBoolean
45import com.fasterxml.jackson.databind.DeserializationFeature
56import com.fasterxml.jackson.databind.JsonSerializer
67import com.fasterxml.jackson.databind.Module
@@ -36,20 +37,27 @@ internal class KotlinAnnotationIntrospector(
3637 // TODO: implement nullIsSameAsDefault flag, which represents when TRUE that if something has a default value, it can be passed a null to default it
3738 // this likely impacts this class to be accurate about what COULD be considered required
3839
40+ // If a new isRequired is explicitly specified or the old required is true, those values take precedence.
41+ // In other cases, override is done by KotlinModule.
42+ private fun JsonProperty.forceRequiredByAnnotation (): Boolean? = when {
43+ isRequired != OptBoolean .DEFAULT -> isRequired.asBoolean()
44+ required -> true
45+ else -> null
46+ }
47+
48+ private fun AccessibleObject.forceRequiredByAnnotation (): Boolean? =
49+ getAnnotation(JsonProperty ::class .java)?.forceRequiredByAnnotation()
50+
3951 override fun hasRequiredMarker (
4052 m : AnnotatedMember
4153 ): Boolean? = m.takeIf { it.member.declaringClass.isKotlinClass() }?.let { _ ->
4254 cache.javaMemberIsRequired(m) {
4355 try {
44- when {
45- nullToEmptyCollection && m.type.isCollectionLikeType -> false
46- nullToEmptyMap && m.type.isMapLikeType -> false
47- else -> when (m) {
48- is AnnotatedField -> m.hasRequiredMarker()
49- is AnnotatedMethod -> m.hasRequiredMarker()
50- is AnnotatedParameter -> m.hasRequiredMarker()
51- else -> null
52- }
56+ when (m) {
57+ is AnnotatedField -> m.hasRequiredMarker()
58+ is AnnotatedMethod -> m.hasRequiredMarker()
59+ is AnnotatedParameter -> m.hasRequiredMarker()
60+ else -> null
5361 }
5462 } catch (_: UnsupportedOperationException ) {
5563 null
@@ -100,28 +108,9 @@ internal class KotlinAnnotationIntrospector(
100108 }
101109
102110 private fun AnnotatedField.hasRequiredMarker (): Boolean? {
103- val byAnnotation = (member as Field ).isRequiredByAnnotation()
104- val byNullability = (member as Field ).kotlinProperty?.returnType?.isRequired()
105-
106- return requiredAnnotationOrNullability(byAnnotation, byNullability)
107- }
108-
109- private fun AccessibleObject.isRequiredByAnnotation (): Boolean? = annotations
110- .firstOrNull { it.annotationClass == JsonProperty ::class }
111- ?.let { it as JsonProperty }
112- ?.required
113-
114- private fun requiredAnnotationOrNullability (byAnnotation : Boolean? , byNullability : Boolean? ): Boolean? {
115- if (byAnnotation != null && byNullability != null ) {
116- return byAnnotation || byNullability
117- } else if (byNullability != null ) {
118- return byNullability
119- }
120- return byAnnotation
121- }
122-
123- private fun Method.isRequiredByAnnotation (): Boolean? {
124- return (this .annotations.firstOrNull { it.annotationClass.java == JsonProperty ::class .java } as ? JsonProperty )?.required
111+ val field = member as Field
112+ return field.forceRequiredByAnnotation()
113+ ? : field.kotlinProperty?.returnType?.isRequired()
125114 }
126115
127116 // Since Kotlin's property has the same Type for each field, getter, and setter,
@@ -136,33 +125,35 @@ internal class KotlinAnnotationIntrospector(
136125 private fun AnnotatedMethod.getRequiredMarkerFromCorrespondingAccessor (): Boolean? {
137126 member.declaringClass.kotlin.declaredMemberProperties.forEach { kProperty ->
138127 if (kProperty.javaGetter == this .member || (kProperty as ? KMutableProperty1 )?.javaSetter == this .member) {
139- val byAnnotation = this .member.isRequiredByAnnotation()
140- val byNullability = kProperty.isRequiredByNullability()
141- return requiredAnnotationOrNullability(byAnnotation, byNullability)
128+ return member.forceRequiredByAnnotation() ? : kProperty.isRequiredByNullability()
142129 }
143130 }
144131 return null
145132 }
146133
147134 // Is the member method a regular method of the data class or
148135 private fun Method.getRequiredMarkerFromAccessorLikeMethod (): Boolean? = cache.kotlinFromJava(this )?.let { func ->
149- val byAnnotation = this .isRequiredByAnnotation()
150- return when {
151- func.isGetterLike() -> requiredAnnotationOrNullability(byAnnotation, func.returnType.isRequired())
152- func.isSetterLike() -> requiredAnnotationOrNullability(byAnnotation, func.valueParameters[0 ].isRequired())
136+ forceRequiredByAnnotation() ? : when {
137+ func.isGetterLike() -> func.returnType.isRequired()
138+ // If nullToEmpty could be supported for setters,
139+ // a branch similar to AnnotatedParameter.hasRequiredMarker should be added.
140+ func.isSetterLike() -> func.valueParameters[0 ].isRequired()
153141 else -> null
154142 }
155143 }
156144
157145 private fun KFunction <* >.isGetterLike (): Boolean = parameters.size == 1
158146 private fun KFunction <* >.isSetterLike (): Boolean = parameters.size == 2 && returnType == UNIT_TYPE
159147
160- private fun AnnotatedParameter.hasRequiredMarker (): Boolean? {
161- val byAnnotation = this .getAnnotation(JsonProperty ::class .java)?.required
162- val byNullability = cache.findKotlinParameter(this )?.isRequired()
163-
164- return requiredAnnotationOrNullability(byAnnotation, byNullability)
165- }
148+ private fun AnnotatedParameter.hasRequiredMarker (): Boolean? = getAnnotation(JsonProperty ::class .java)
149+ ?.forceRequiredByAnnotation()
150+ ? : run {
151+ when {
152+ nullToEmptyCollection && type.isCollectionLikeType -> false
153+ nullToEmptyMap && type.isMapLikeType -> false
154+ else -> cache.findKotlinParameter(this )?.isRequired()
155+ }
156+ }
166157
167158 private fun AnnotatedMethod.findValueClassReturnType () = cache.findValueClassReturnType(this )
168159
0 commit comments