Skip to content

Commit 8814157

Browse files
committed
fix tests and add annotation check by simple name string
1 parent ece6158 commit 8814157

3 files changed

Lines changed: 81 additions & 30 deletions

File tree

pom.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45

56
<parent>

src/main/java/it/aboutbits/springboot/toolbox/swagger/customization/default_not_null/NullableCustomizer.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,13 @@ private static boolean isNullable(
130130
AnnotatedType annotatedType,
131131
Annotation[] annotations
132132
) {
133-
if (annotatedType.isAnnotationPresent(org.jspecify.annotations.Nullable.class)) {
134-
return true;
133+
for (var annotation : annotatedType.getAnnotations()) {
134+
if (annotation.annotationType().getSimpleName().equals("Nullable")) {
135+
return true;
136+
}
135137
}
136138
for (var annotation : annotations) {
137-
var name = annotation.annotationType().getName();
138-
if (name.equals("org.springframework.lang.Nullable") || name.equals("jakarta.annotation.Nullable")) {
139+
if (annotation.annotationType().getSimpleName().equals("Nullable")) {
139140
return true;
140141
}
141142
}

src/test/java/it/aboutbits/springboot/toolbox/swagger/customization/default_not_null/NullableCustomizerTest.java

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import org.jspecify.annotations.NullUnmarked;
88
import org.junit.jupiter.api.Test;
99

10-
import java.util.List;
10+
import java.lang.annotation.Retention;
11+
import java.lang.annotation.RetentionPolicy;
1112

12-
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
13-
import static org.junit.jupiter.api.Assertions.assertTrue;
13+
import static org.assertj.core.api.Assertions.assertThat;
1414

1515
@NullUnmarked
1616
class NullableCustomizerTest {
@@ -52,6 +52,7 @@ public String directMethod() {
5252

5353
@Test
5454
void shouldFindFieldInSuperClass() {
55+
// given
5556
var customizer = new NullableCustomizer();
5657
var openApi = new OpenAPI();
5758
var components = new Components();
@@ -64,15 +65,19 @@ void shouldFindFieldInSuperClass() {
6465
components.addSchemas(SubClass.class.getName(), subClassSchema);
6566
openApi.setComponents(components);
6667

67-
assertDoesNotThrow(() -> customizer.customise(openApi));
68+
// when
69+
customizer.customise(openApi);
6870

69-
List<String> required = subClassSchema.getRequired();
70-
assertTrue(required != null && required.contains("subField"), "subField should be required");
71-
assertTrue(required == null || !required.contains("baseField"), "baseField should NOT be required");
71+
// then
72+
var required = subClassSchema.getRequired();
73+
74+
assertThat(required).as("subField should be required").contains("subField");
75+
assertThat(required).as("baseField should NOT be required").doesNotContain("baseField");
7276
}
7377

7478
@Test
7579
void shouldFindAnnotationOnGetter() {
80+
// given
7681
var customizer = new NullableCustomizer();
7782
var openApi = new OpenAPI();
7883
var components = new Components();
@@ -84,14 +89,17 @@ void shouldFindAnnotationOnGetter() {
8489
components.addSchemas(MethodAnnotated.class.getName(), schema);
8590
openApi.setComponents(components);
8691

87-
assertDoesNotThrow(() -> customizer.customise(openApi));
92+
// when
93+
customizer.customise(openApi);
8894

89-
List<String> required = schema.getRequired();
90-
assertTrue(required == null || !required.contains("annotatedGetter"), "annotatedGetter should NOT be required");
95+
// then
96+
var required = schema.getRequired();
97+
assertThat(required).as("annotatedGetter should NOT be required").isNullOrEmpty();
9198
}
9299

93100
@Test
94101
void shouldFindAnnotationOnDirectMethod() {
102+
// given
95103
var customizer = new NullableCustomizer();
96104
var openApi = new OpenAPI();
97105
var components = new Components();
@@ -103,14 +111,17 @@ void shouldFindAnnotationOnDirectMethod() {
103111
components.addSchemas(DirectMethodAnnotated.class.getName(), schema);
104112
openApi.setComponents(components);
105113

106-
assertDoesNotThrow(() -> customizer.customise(openApi));
114+
// when
115+
customizer.customise(openApi);
107116

108-
List<String> required = schema.getRequired();
109-
assertTrue(required == null || !required.contains("directMethod"), "directMethod should NOT be required");
117+
// then
118+
var required = schema.getRequired();
119+
assertThat(required).as("directMethod should NOT be required").isNullOrEmpty();
110120
}
111121

112122
@Test
113123
void shouldHandleConcatenatedFqns() {
124+
// given
114125
var customizer = new NullableCustomizer();
115126
var openApi = new OpenAPI();
116127
var components = new Components();
@@ -124,17 +135,17 @@ void shouldHandleConcatenatedFqns() {
124135
components.addSchemas(concatenatedFqn, schema);
125136
openApi.setComponents(components);
126137

127-
assertDoesNotThrow(() -> customizer.customise(openApi));
138+
// when
139+
customizer.customise(openApi);
128140

129-
List<String> required = schema.getRequired();
130-
assertTrue(
131-
required == null || !required.contains("baseField"),
132-
"baseField should NOT be required even with concatenated FQN"
133-
);
141+
// then
142+
var required = schema.getRequired();
143+
assertThat(required).as("baseField should NOT be required even with concatenated FQN").isNullOrEmpty();
134144
}
135145

136146
@Test
137147
void shouldNotThrowWhenFieldNotFound() {
148+
// given
138149
var customizer = new NullableCustomizer();
139150
var openApi = new OpenAPI();
140151
var components = new Components();
@@ -146,12 +157,50 @@ void shouldNotThrowWhenFieldNotFound() {
146157
components.addSchemas(SubClass.class.getName(), schema);
147158
openApi.setComponents(components);
148159

149-
assertDoesNotThrow(() -> customizer.customise(openApi));
160+
// when
161+
customizer.customise(openApi);
162+
163+
// then
164+
var required = schema.getRequired();
165+
assertThat(required).as("nonExistent field should be considered required if not found and not nullable")
166+
.contains("nonExistent");
167+
}
168+
169+
@Test
170+
void shouldFindCustomNullableAnnotation() {
171+
// given
172+
var customizer = new NullableCustomizer();
173+
var openApi = new OpenAPI();
174+
var components = new Components();
175+
176+
var schema = new Schema<Object>();
177+
schema.setName(CustomNullableClass.class.getName());
178+
schema.addProperty("customNullableField", new StringSchema());
179+
180+
components.addSchemas(CustomNullableClass.class.getName(), schema);
181+
openApi.setComponents(components);
182+
183+
// when
184+
customizer.customise(openApi);
185+
186+
// then
187+
var required = schema.getRequired();
188+
assertThat(required).as("customNullableField should NOT be required").isNullOrEmpty();
189+
}
190+
191+
public static class Nest {
192+
@Retention(RetentionPolicy.RUNTIME)
193+
public @interface Nullable {
194+
}
195+
}
150196

151-
List<String> required = schema.getRequired();
152-
assertTrue(
153-
required != null && required.contains("nonExistent"),
154-
"nonExistent field should be considered required if not found and not nullable"
155-
);
197+
public static class CustomNullableClass {
198+
@Nest.Nullable
199+
private String customNullableField;
200+
201+
@SuppressWarnings("NullAway")
202+
public String getCustomNullableField() {
203+
return customNullableField;
204+
}
156205
}
157206
}

0 commit comments

Comments
 (0)