1
1
package com.fasterxml.jackson.module.kotlin.test.github
2
2
3
+ import com.fasterxml.jackson.annotation.JsonProperty
4
+ import com.fasterxml.jackson.annotation.OptBoolean
3
5
import com.fasterxml.jackson.databind.BeanDescription
4
6
import com.fasterxml.jackson.databind.ObjectMapper
5
7
import com.fasterxml.jackson.module.kotlin.KotlinFeature
8
+ import com.fasterxml.jackson.module.kotlin.defaultMapper
6
9
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
10
+ import kotlin.reflect.full.memberProperties
7
11
import kotlin.test.Test
12
+ import kotlin.test.assertEquals
8
13
import kotlin.test.assertTrue
9
14
10
15
class GitHub922 {
16
+ companion object {
17
+ val nullToEmptyMapper = jacksonObjectMapper {
18
+ enable(KotlinFeature .NullToEmptyCollection )
19
+ enable(KotlinFeature .NullToEmptyMap )
20
+ }
21
+ }
22
+
11
23
private inline fun <reified T : Any > ObjectMapper.introspectSerialization (): BeanDescription =
12
24
serializationConfig.introspect(serializationConfig.constructType(T ::class .java))
13
25
@@ -19,14 +31,145 @@ class GitHub922 {
19
31
20
32
@Test
21
33
fun `nullToEmpty does not override specification by Java annotation` () {
22
- val mapper = jacksonObjectMapper {
23
- enable(KotlinFeature .NullToEmptyCollection )
24
- enable(KotlinFeature .NullToEmptyMap )
25
- }
34
+ val defaultDesc = defaultMapper.introspectDeserialization<GitHub922RequiredCollectionsDtoJava >()
35
+
36
+ assertTrue(defaultDesc.isRequired(" list" ))
37
+ assertTrue(defaultDesc.isRequired(" map" ))
38
+
39
+ val nullToEmptyDesc = nullToEmptyMapper.introspectDeserialization<GitHub922RequiredCollectionsDtoJava >()
40
+
41
+ assertTrue(nullToEmptyDesc.isRequired(" list" ))
42
+ assertTrue(nullToEmptyDesc.isRequired(" map" ))
43
+ }
44
+
45
+ data class RequiredCollectionsDto1 (
46
+ @JsonProperty(required = true ) val list : List <String >,
47
+ @JsonProperty(required = true ) val map : Map <String , String >
48
+ )
26
49
27
- val desc = mapper.introspectDeserialization<GitHub922RequiredCollectionsDtoJava >()
50
+ data class RequiredCollectionsDto2 (
51
+ @JsonProperty(isRequired = OptBoolean .TRUE ) val list : List <String >,
52
+ @JsonProperty(isRequired = OptBoolean .TRUE ) val map : Map <String , String >
53
+ )
54
+
55
+ @Test
56
+ fun `nullToEmpty does not override specification by annotation` () {
57
+ val defaultDesc1 = defaultMapper.introspectDeserialization<RequiredCollectionsDto1 >()
58
+
59
+ assertTrue(defaultDesc1.isRequired(" list" ))
60
+ assertTrue(defaultDesc1.isRequired(" map" ))
61
+
62
+ val nullToEmptyDesc1 = nullToEmptyMapper.introspectDeserialization<RequiredCollectionsDto1 >()
63
+
64
+ assertTrue(nullToEmptyDesc1.isRequired(" list" ))
65
+ assertTrue(nullToEmptyDesc1.isRequired(" map" ))
66
+
67
+ val defaultDesc2 = defaultMapper.introspectDeserialization<RequiredCollectionsDto2 >()
68
+
69
+ assertTrue(defaultDesc2.isRequired(" list" ))
70
+ assertTrue(defaultDesc2.isRequired(" map" ))
71
+
72
+ val nullToEmptyDesc2 = nullToEmptyMapper.introspectDeserialization<RequiredCollectionsDto2 >()
73
+
74
+ assertTrue(nullToEmptyDesc2.isRequired(" list" ))
75
+ assertTrue(nullToEmptyDesc2.isRequired(" map" ))
76
+ }
77
+
78
+ data class CollectionsDto (val list : List <String >, val map : Map <String , String >)
79
+
80
+ @Test
81
+ fun `nullToEmpty does not affect for serialization` () {
82
+ val defaultDesc = defaultMapper.introspectSerialization<CollectionsDto >()
28
83
29
- assertTrue(desc.isRequired(" list" ))
30
- assertTrue(desc.isRequired(" map" ))
84
+ assertTrue(defaultDesc.isRequired(" list" ))
85
+ assertTrue(defaultDesc.isRequired(" map" ))
86
+
87
+ val nullToEmptyDesc = nullToEmptyMapper.introspectSerialization<CollectionsDto >()
88
+
89
+ assertTrue(nullToEmptyDesc.isRequired(" list" ))
90
+ assertTrue(nullToEmptyDesc.isRequired(" map" ))
91
+ }
92
+
93
+ class SetterCollectionsDto {
94
+ lateinit var list: List <String >
95
+ lateinit var map: Map <String , String >
96
+ }
97
+
98
+ @Test
99
+ fun `nullToEmpty does not affect for setter` () {
100
+ val defaultDesc = defaultMapper.introspectDeserialization<SetterCollectionsDto >()
101
+
102
+ assertTrue(defaultDesc.isRequired(" list" ))
103
+ assertTrue(defaultDesc.isRequired(" map" ))
104
+
105
+ val nullToEmptyDesc = nullToEmptyMapper.introspectDeserialization<SetterCollectionsDto >()
106
+
107
+ assertTrue(nullToEmptyDesc.isRequired(" list" ))
108
+ assertTrue(nullToEmptyDesc.isRequired(" map" ))
109
+ }
110
+
111
+ class FieldCollectionsDto {
112
+ @JvmField
113
+ var list: List <String > = emptyList()
114
+ @JvmField
115
+ var map: Map <String , String > = emptyMap()
116
+ }
117
+
118
+ @Test
119
+ fun `nullToEmpty does not affect for field` () {
120
+ val defaultDesc = defaultMapper.introspectDeserialization<FieldCollectionsDto >()
121
+
122
+ assertTrue(defaultDesc.isRequired(" list" ))
123
+ assertTrue(defaultDesc.isRequired(" map" ))
124
+
125
+ val nullToEmptyDesc = nullToEmptyMapper.introspectDeserialization<FieldCollectionsDto >()
126
+
127
+ assertTrue(nullToEmptyDesc.isRequired(" list" ))
128
+ assertTrue(nullToEmptyDesc.isRequired(" map" ))
129
+ }
130
+
131
+ // isRequired_required_nullability_expected
132
+ @Suppress(" PropertyName" )
133
+ data class IsRequiredDto (
134
+ // region: isRequired takes precedence
135
+ @JsonProperty(isRequired = OptBoolean .FALSE , required = false )
136
+ val FALSE_false_nullable_false : String? ,
137
+ @JsonProperty(isRequired = OptBoolean .FALSE , required = false )
138
+ val FALSE_false_nonNull_false : String ,
139
+ @JsonProperty(isRequired = OptBoolean .FALSE , required = true )
140
+ val FALSE_true_nullable_false : String? ,
141
+ @JsonProperty(isRequired = OptBoolean .FALSE , required = true )
142
+ val FALSE_true_nonNull_false : String ,
143
+ @JsonProperty(isRequired = OptBoolean .TRUE , required = false )
144
+ val TRUE_false_nullable_true : String? ,
145
+ @JsonProperty(isRequired = OptBoolean .TRUE , required = false )
146
+ val TRUE_false_nonNull_true : String ,
147
+ @JsonProperty(isRequired = OptBoolean .TRUE , required = true )
148
+ val TRUE_true_nullable_true : String? ,
149
+ @JsonProperty(isRequired = OptBoolean .TRUE , required = true )
150
+ val TRUE_true_nonNull_true : String ,
151
+ // endregion
152
+ // region: If isRequired is the default, only overrides by required = true will work.
153
+ @JsonProperty(isRequired = OptBoolean .DEFAULT , required = false )
154
+ val DEFAULT_false_nullable_false : String? ,
155
+ @JsonProperty(isRequired = OptBoolean .DEFAULT , required = false )
156
+ val DEFAULT_false_nonNull_true : String ,
157
+ @JsonProperty(isRequired = OptBoolean .DEFAULT , required = true )
158
+ val DEFAULT_true_nullable_true : String? ,
159
+ @JsonProperty(isRequired = OptBoolean .DEFAULT , required = true )
160
+ val DEFAULT_true_nonNull_true : String ,
161
+ // endregion
162
+ )
163
+
164
+ @Test
165
+ fun `JsonProperty properly overrides required` () {
166
+ val desc = defaultMapper.introspectDeserialization<IsRequiredDto >()
167
+
168
+ IsRequiredDto ::class .memberProperties.forEach { prop ->
169
+ val name = prop.name
170
+ val expected = name.split(" _" ).last().toBoolean()
171
+
172
+ assertEquals(expected, desc.isRequired(name), name)
173
+ }
31
174
}
32
175
}
0 commit comments