1
1
package com.fasterxml.jackson.module.kotlin
2
2
3
3
import com.fasterxml.jackson.annotation.JsonProperty
4
+ import com.fasterxml.jackson.annotation.OptBoolean
4
5
import com.fasterxml.jackson.databind.DeserializationFeature
5
6
import com.fasterxml.jackson.databind.JsonSerializer
6
7
import com.fasterxml.jackson.databind.Module
@@ -36,20 +37,27 @@ internal class KotlinAnnotationIntrospector(
36
37
// TODO: implement nullIsSameAsDefault flag, which represents when TRUE that if something has a default value, it can be passed a null to default it
37
38
// this likely impacts this class to be accurate about what COULD be considered required
38
39
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
+
39
51
override fun hasRequiredMarker (
40
52
m : AnnotatedMember
41
53
): Boolean? = m.takeIf { it.member.declaringClass.isKotlinClass() }?.let { _ ->
42
54
cache.javaMemberIsRequired(m) {
43
55
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
53
61
}
54
62
} catch (_: UnsupportedOperationException ) {
55
63
null
@@ -100,28 +108,9 @@ internal class KotlinAnnotationIntrospector(
100
108
}
101
109
102
110
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()
125
114
}
126
115
127
116
// Since Kotlin's property has the same Type for each field, getter, and setter,
@@ -136,33 +125,35 @@ internal class KotlinAnnotationIntrospector(
136
125
private fun AnnotatedMethod.getRequiredMarkerFromCorrespondingAccessor (): Boolean? {
137
126
member.declaringClass.kotlin.declaredMemberProperties.forEach { kProperty ->
138
127
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()
142
129
}
143
130
}
144
131
return null
145
132
}
146
133
147
134
// Is the member method a regular method of the data class or
148
135
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()
153
141
else -> null
154
142
}
155
143
}
156
144
157
145
private fun KFunction <* >.isGetterLike (): Boolean = parameters.size == 1
158
146
private fun KFunction <* >.isSetterLike (): Boolean = parameters.size == 2 && returnType == UNIT_TYPE
159
147
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
+ }
166
157
167
158
private fun AnnotatedMethod.findValueClassReturnType () = cache.findValueClassReturnType(this )
168
159
0 commit comments