11package tools.jackson.module.kotlin.test.github
22
3+ import com.fasterxml.jackson.annotation.JsonProperty
4+ import com.fasterxml.jackson.annotation.OptBoolean
35import tools.jackson.databind.BeanDescription
46import tools.jackson.databind.ObjectMapper
57import tools.jackson.module.kotlin.KotlinFeature
8+ import tools.jackson.module.kotlin.defaultMapper
69import tools.jackson.module.kotlin.jacksonObjectMapper
10+ import kotlin.reflect.full.memberProperties
711import kotlin.test.Test
12+ import kotlin.test.assertEquals
813import kotlin.test.assertTrue
914
1015class GitHub922 {
16+ companion object {
17+ val nullToEmptyMapper = jacksonObjectMapper {
18+ enable(KotlinFeature .NullToEmptyCollection )
19+ enable(KotlinFeature .NullToEmptyMap )
20+ }
21+ }
22+
1123 private inline fun <reified T : Any > ObjectMapper.introspectSerialization (): BeanDescription =
1224 _serializationContext ().introspectBeanDescription(_serializationContext ().constructType(T ::class .java))
1325
@@ -19,14 +31,145 @@ class GitHub922 {
1931
2032 @Test
2133 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+ )
2649
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 >()
2883
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+ }
31174 }
32175}
0 commit comments