11package tools.jackson.module.kotlin
22
33import com.fasterxml.jackson.annotation.JsonProperty
4+ import com.fasterxml.jackson.annotation.OptBoolean
45import tools.jackson.databind.DeserializationFeature
56import tools.jackson.databind.JacksonModule
67import tools.jackson.databind.cfg.MapperConfig
@@ -42,23 +43,33 @@ internal class KotlinAnnotationIntrospector(
4243 // TODO: implement nullIsSameAsDefault flag, which represents when TRUE that if something has a default value, it can be passed a null to default it
4344 // this likely impacts this class to be accurate about what COULD be considered required
4445
45- override fun hasRequiredMarker (cfg : MapperConfig <* >, m : AnnotatedMember ): Boolean? =
46+ // If a new isRequired is explicitly specified or the old required is true, those values take precedence.
47+ // In other cases, override is done by KotlinModule.
48+ private fun JsonProperty.forceRequiredByAnnotation (): Boolean? = when {
49+ isRequired != OptBoolean .DEFAULT -> isRequired.asBoolean()
50+ required -> true
51+ else -> null
52+ }
53+
54+ private fun AccessibleObject.forceRequiredByAnnotation (): Boolean? =
55+ getAnnotation(JsonProperty ::class .java)?.forceRequiredByAnnotation()
56+
57+ override fun hasRequiredMarker (
58+ cfg : MapperConfig <* >,
59+ m : AnnotatedMember
60+ ): Boolean? = m.takeIf { it.member.declaringClass.isKotlinClass() }?.let { _ ->
4661 cache.javaMemberIsRequired(m) {
4762 try {
48- when {
49- nullToEmptyCollection && m.type.isCollectionLikeType -> false
50- nullToEmptyMap && m.type.isMapLikeType -> false
51- m.member.declaringClass.isKotlinClass() -> when (m) {
52- is AnnotatedField -> m.hasRequiredMarker()
53- is AnnotatedMethod -> m.hasRequiredMarker()
54- is AnnotatedParameter -> m.hasRequiredMarker()
55- else -> null
56- }
63+ when (m) {
64+ is AnnotatedField -> m.hasRequiredMarker()
65+ is AnnotatedMethod -> m.hasRequiredMarker()
66+ is AnnotatedParameter -> m.hasRequiredMarker()
5767 else -> null
5868 }
59- } catch (ex : UnsupportedOperationException ) {
69+ } catch (_ : UnsupportedOperationException ) {
6070 null
6171 }
72+ }
6273 }
6374
6475 override fun findSerializationConverter (config : MapperConfig <* >? , a : Annotated ): Converter <* , * >? = when (a) {
@@ -104,28 +115,9 @@ internal class KotlinAnnotationIntrospector(
104115 }
105116
106117 private fun AnnotatedField.hasRequiredMarker (): Boolean? {
107- val byAnnotation = (member as Field ).isRequiredByAnnotation()
108- val byNullability = (member as Field ).kotlinProperty?.returnType?.isRequired()
109-
110- return requiredAnnotationOrNullability(byAnnotation, byNullability)
111- }
112-
113- private fun AccessibleObject.isRequiredByAnnotation (): Boolean? = annotations
114- ?.firstOrNull { it.annotationClass == JsonProperty ::class }
115- ?.let { it as JsonProperty }
116- ?.required
117-
118- private fun requiredAnnotationOrNullability (byAnnotation : Boolean? , byNullability : Boolean? ): Boolean? {
119- if (byAnnotation != null && byNullability != null ) {
120- return byAnnotation || byNullability
121- } else if (byNullability != null ) {
122- return byNullability
123- }
124- return byAnnotation
125- }
126-
127- private fun Method.isRequiredByAnnotation (): Boolean? {
128- return (this .annotations.firstOrNull { it.annotationClass.java == JsonProperty ::class .java } as ? JsonProperty )?.required
118+ val field = member as Field
119+ return field.forceRequiredByAnnotation()
120+ ? : field.kotlinProperty?.returnType?.isRequired()
129121 }
130122
131123 // Since Kotlin's property has the same Type for each field, getter, and setter,
@@ -140,33 +132,35 @@ internal class KotlinAnnotationIntrospector(
140132 private fun AnnotatedMethod.getRequiredMarkerFromCorrespondingAccessor (): Boolean? {
141133 member.declaringClass.kotlin.declaredMemberProperties.forEach { kProperty ->
142134 if (kProperty.javaGetter == this .member || (kProperty as ? KMutableProperty1 )?.javaSetter == this .member) {
143- val byAnnotation = this .member.isRequiredByAnnotation()
144- val byNullability = kProperty.isRequiredByNullability()
145- return requiredAnnotationOrNullability(byAnnotation, byNullability)
135+ return member.forceRequiredByAnnotation() ? : kProperty.isRequiredByNullability()
146136 }
147137 }
148138 return null
149139 }
150140
151141 // Is the member method a regular method of the data class or
152142 private fun Method.getRequiredMarkerFromAccessorLikeMethod (): Boolean? = cache.kotlinFromJava(this )?.let { func ->
153- val byAnnotation = this .isRequiredByAnnotation()
154- return when {
155- func.isGetterLike() -> requiredAnnotationOrNullability(byAnnotation, func.returnType.isRequired())
156- func.isSetterLike() -> requiredAnnotationOrNullability(byAnnotation, func.valueParameters[0 ].isRequired())
143+ forceRequiredByAnnotation() ? : when {
144+ func.isGetterLike() -> func.returnType.isRequired()
145+ // If nullToEmpty could be supported for setters,
146+ // a branch similar to AnnotatedParameter.hasRequiredMarker should be added.
147+ func.isSetterLike() -> func.valueParameters[0 ].isRequired()
157148 else -> null
158149 }
159150 }
160151
161152 private fun KFunction <* >.isGetterLike (): Boolean = parameters.size == 1
162153 private fun KFunction <* >.isSetterLike (): Boolean = parameters.size == 2 && returnType == UNIT_TYPE
163154
164- private fun AnnotatedParameter.hasRequiredMarker (): Boolean? {
165- val byAnnotation = this .getAnnotation(JsonProperty ::class .java)?.required
166- val byNullability = cache.findKotlinParameter(this )?.isRequired()
167-
168- return requiredAnnotationOrNullability(byAnnotation, byNullability)
169- }
155+ private fun AnnotatedParameter.hasRequiredMarker (): Boolean? = getAnnotation(JsonProperty ::class .java)
156+ ?.forceRequiredByAnnotation()
157+ ? : run {
158+ when {
159+ nullToEmptyCollection && type.isCollectionLikeType -> false
160+ nullToEmptyMap && type.isMapLikeType -> false
161+ else -> cache.findKotlinParameter(this )?.isRequired()
162+ }
163+ }
170164
171165 private fun AnnotatedMethod.findValueClassReturnType () = cache.findValueClassReturnType(this )
172166
0 commit comments