88import org .jspecify .annotations .Nullable ;
99import org .junit .jupiter .api .Test ;
1010
11- import java .util .List ;
11+ import java .lang .annotation .Retention ;
12+ import java .lang .annotation .RetentionPolicy ;
1213
13- import static org .junit .jupiter .api .Assertions .assertDoesNotThrow ;
14- import static org .junit .jupiter .api .Assertions .assertTrue ;
14+ import static org .assertj .core .api .Assertions .assertThat ;
1515
1616@ NullUnmarked
1717class NullableCustomizerTest {
@@ -53,6 +53,7 @@ public String directMethod() {
5353
5454 @ Test
5555 void shouldFindFieldInSuperClass () {
56+ // given
5657 var customizer = new NullableCustomizer ();
5758 var openApi = new OpenAPI ();
5859 var components = new Components ();
@@ -65,15 +66,19 @@ void shouldFindFieldInSuperClass() {
6566 components .addSchemas (SubClass .class .getName (), subClassSchema );
6667 openApi .setComponents (components );
6768
68- assertDoesNotThrow (() -> customizer .customise (openApi ));
69+ // when
70+ customizer .customise (openApi );
6971
70- List <String > required = subClassSchema .getRequired ();
71- assertTrue (required != null && required .contains ("subField" ), "subField should be required" );
72- assertTrue (required == null || !required .contains ("baseField" ), "baseField should NOT be required" );
72+ // then
73+ var required = subClassSchema .getRequired ();
74+
75+ assertThat (required ).as ("subField should be required" ).contains ("subField" );
76+ assertThat (required ).as ("baseField should NOT be required" ).doesNotContain ("baseField" );
7377 }
7478
7579 @ Test
7680 void shouldFindAnnotationOnGetter () {
81+ // given
7782 var customizer = new NullableCustomizer ();
7883 var openApi = new OpenAPI ();
7984 var components = new Components ();
@@ -85,14 +90,17 @@ void shouldFindAnnotationOnGetter() {
8590 components .addSchemas (MethodAnnotated .class .getName (), schema );
8691 openApi .setComponents (components );
8792
88- assertDoesNotThrow (() -> customizer .customise (openApi ));
93+ // when
94+ customizer .customise (openApi );
8995
90- List <String > required = schema .getRequired ();
91- assertTrue (required == null || !required .contains ("annotatedGetter" ), "annotatedGetter should NOT be required" );
96+ // then
97+ var required = schema .getRequired ();
98+ assertThat (required ).as ("annotatedGetter should NOT be required" ).isNullOrEmpty ();
9299 }
93100
94101 @ Test
95102 void shouldFindAnnotationOnDirectMethod () {
103+ // given
96104 var customizer = new NullableCustomizer ();
97105 var openApi = new OpenAPI ();
98106 var components = new Components ();
@@ -104,14 +112,17 @@ void shouldFindAnnotationOnDirectMethod() {
104112 components .addSchemas (DirectMethodAnnotated .class .getName (), schema );
105113 openApi .setComponents (components );
106114
107- assertDoesNotThrow (() -> customizer .customise (openApi ));
115+ // when
116+ customizer .customise (openApi );
108117
109- List <String > required = schema .getRequired ();
110- assertTrue (required == null || !required .contains ("directMethod" ), "directMethod should NOT be required" );
118+ // then
119+ var required = schema .getRequired ();
120+ assertThat (required ).as ("directMethod should NOT be required" ).isNullOrEmpty ();
111121 }
112122
113123 @ Test
114124 void shouldHandleConcatenatedFqns () {
125+ // given
115126 var customizer = new NullableCustomizer ();
116127 var openApi = new OpenAPI ();
117128 var components = new Components ();
@@ -125,17 +136,17 @@ void shouldHandleConcatenatedFqns() {
125136 components .addSchemas (concatenatedFqn , schema );
126137 openApi .setComponents (components );
127138
128- assertDoesNotThrow (() -> customizer .customise (openApi ));
139+ // when
140+ customizer .customise (openApi );
129141
130- List <String > required = schema .getRequired ();
131- assertTrue (
132- required == null || !required .contains ("baseField" ),
133- "baseField should NOT be required even with concatenated FQN"
134- );
142+ // then
143+ var required = schema .getRequired ();
144+ assertThat (required ).as ("baseField should NOT be required even with concatenated FQN" ).isNullOrEmpty ();
135145 }
136146
137147 @ Test
138148 void shouldNotThrowWhenFieldNotFound () {
149+ // given
139150 var customizer = new NullableCustomizer ();
140151 var openApi = new OpenAPI ();
141152 var components = new Components ();
@@ -147,12 +158,50 @@ void shouldNotThrowWhenFieldNotFound() {
147158 components .addSchemas (SubClass .class .getName (), schema );
148159 openApi .setComponents (components );
149160
150- assertDoesNotThrow (() -> customizer .customise (openApi ));
161+ // when
162+ customizer .customise (openApi );
163+
164+ // then
165+ var required = schema .getRequired ();
166+ assertThat (required ).as ("nonExistent field should be considered required if not found and not nullable" )
167+ .contains ("nonExistent" );
168+ }
169+
170+ @ Test
171+ void shouldFindCustomNullableAnnotation () {
172+ // given
173+ var customizer = new NullableCustomizer ();
174+ var openApi = new OpenAPI ();
175+ var components = new Components ();
176+
177+ var schema = new Schema <Object >();
178+ schema .setName (CustomNullableClass .class .getName ());
179+ schema .addProperty ("customNullableField" , new StringSchema ());
180+
181+ components .addSchemas (CustomNullableClass .class .getName (), schema );
182+ openApi .setComponents (components );
183+
184+ // when
185+ customizer .customise (openApi );
186+
187+ // then
188+ var required = schema .getRequired ();
189+ assertThat (required ).as ("customNullableField should NOT be required" ).isNullOrEmpty ();
190+ }
191+
192+ public static class Nest {
193+ @ Retention (RetentionPolicy .RUNTIME )
194+ public @interface Nullable {
195+ }
196+ }
151197
152- List <String > required = schema .getRequired ();
153- assertTrue (
154- required != null && required .contains ("nonExistent" ),
155- "nonExistent field should be considered required if not found and not nullable"
156- );
198+ public static class CustomNullableClass {
199+ @ Nest .Nullable
200+ private String customNullableField ;
201+
202+ @ SuppressWarnings ("NullAway" )
203+ public String getCustomNullableField () {
204+ return customNullableField ;
205+ }
157206 }
158207}
0 commit comments