Skip to content

Commit ce6f262

Browse files
Mattias-Sehlstedtewaostrowska
authored andcommitted
fix: do not process a nullable annotation for container items
1 parent ca8b4b5 commit ce6f262

7 files changed

Lines changed: 381 additions & 106 deletions

File tree

modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java

Lines changed: 83 additions & 77 deletions
Large diffs are not rendered by default.

modules/swagger-core/src/test/java/io/swagger/v3/core/converting/ArrayOfSubclassTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import io.swagger.v3.core.converter.ModelConverters;
44
import io.swagger.v3.core.converter.ResolvedSchema;
55
import io.swagger.v3.core.oas.models.ModelWithArrayOfSubclasses;
6+
import io.swagger.v3.core.util.Json;
67
import io.swagger.v3.core.util.Json31;
78

89
import static org.testng.Assert.assertEquals;
910
import static org.testng.Assert.assertNotNull;
11+
12+
import io.swagger.v3.core.util.ResourceUtils;
1013
import org.testng.annotations.Test;
1114

12-
import java.nio.file.Files;
13-
import java.nio.file.Paths;
1415
import com.fasterxml.jackson.databind.ObjectMapper;
1516
import com.fasterxml.jackson.databind.JsonNode;
1617

@@ -21,7 +22,7 @@ public class ArrayOfSubclassTest {
2122
public void extractSubclassArray_oas31() throws Exception {
2223
ResolvedSchema schema = ModelConverters.getInstance(true).readAllAsResolvedSchema(ModelWithArrayOfSubclasses.Holder.class);
2324
assertNotNull(schema);
24-
String expectedJson = new String(Files.readAllBytes(Paths.get("src/test/resources/converting/ArrayOfSubclassTest_expected31.json")));
25+
String expectedJson = ResourceUtils.loadClassResource(getClass(), "converting/ArrayOfSubclassTest_expected31.json");
2526
String actualJson = Json31.pretty(schema);
2627
ObjectMapper mapper = new ObjectMapper();
2728
JsonNode expectedNode = mapper.readTree(expectedJson);
@@ -33,8 +34,8 @@ public void extractSubclassArray_oas31() throws Exception {
3334
public void extractSubclassArray_oas30() throws Exception {
3435
ResolvedSchema schema = ModelConverters.getInstance(false).readAllAsResolvedSchema(ModelWithArrayOfSubclasses.Holder.class);
3536
assertNotNull(schema);
36-
String expectedJson = new String(Files.readAllBytes(Paths.get("src/test/resources/converting/ArrayOfSubclassTest_expected30.json")));
37-
String actualJson = Json31.pretty(schema);
37+
String expectedJson = ResourceUtils.loadClassResource(getClass(), "converting/ArrayOfSubclassTest_expected30.json");
38+
String actualJson = Json.pretty(schema);
3839
ObjectMapper mapper = new ObjectMapper();
3940
JsonNode expectedNode = mapper.readTree(expectedJson);
4041
JsonNode actualNode = mapper.readTree(actualJson);

modules/swagger-core/src/test/java/io/swagger/v3/core/issues/Issue5001Test.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import io.swagger.v3.core.converter.AnnotatedType;
44
import io.swagger.v3.core.converter.ModelConverterContextImpl;
5+
import io.swagger.v3.core.converter.ModelConverters;
6+
import io.swagger.v3.core.converter.ResolvedSchema;
57
import io.swagger.v3.core.jackson.ModelResolver;
68
import io.swagger.v3.core.util.Configuration;
79
import io.swagger.v3.core.util.Json;
@@ -10,6 +12,7 @@
1012
import org.testng.annotations.Test;
1113

1214
import javax.annotation.Nullable;
15+
import java.util.List;
1316
import java.util.Set;
1417

1518
import static org.testng.Assert.*;
@@ -18,11 +21,11 @@
1821
* Reproduces GitHub Issue #5001
1922
* Native support for @Nullable annotations to generate proper nullable types
2023
*
21-
* Tests that @Nullable annotation is recognized and generates appropriate nullable output:
24+
* <p>Tests that @Nullable annotation is recognized and generates appropriate nullable output:
2225
* - OAS 3.0: nullable keyword
2326
* - OAS 3.1: type array with "null"
2427
*
25-
* Note: This test uses javax.annotation.Nullable which is automatically transformed to
28+
* <p>Note: This test uses javax.annotation.Nullable which is automatically transformed to
2629
* jakarta.annotation.Nullable in the swagger-core-jakarta module via the Eclipse Transformer.
2730
*
2831
* @see <a href="https://github.com/swagger-api/swagger-core/issues/5001">...</a>
@@ -33,7 +36,7 @@ public class Issue5001Test {
3336
* Tests @Nullable annotation with OAS 3.1 (type array output)
3437
*/
3538
@Test
36-
public void testNullableWithOAS31() throws Exception {
39+
public void testNullableWithOAS31() {
3740
final ModelResolver modelResolver = new ModelResolver(Json31.mapper());
3841
Configuration configuration = new Configuration();
3942
configuration.setOpenAPI31(true);
@@ -72,7 +75,7 @@ public void testNullableWithOAS31() throws Exception {
7275
* Tests @Nullable annotation with OAS 3.0 (nullable keyword output)
7376
*/
7477
@Test
75-
public void testNullableWithOAS30() throws Exception {
78+
public void testNullableWithOAS30() {
7679
final ModelResolver modelResolver = new ModelResolver(Json.mapper());
7780
Configuration configuration = new Configuration();
7881
configuration.setOpenAPI31(false);
@@ -103,7 +106,7 @@ public void testNullableWithOAS30() throws Exception {
103106
* Tests explicit @Schema annotations with OAS 3.1
104107
*/
105108
@Test
106-
public void testExplicitSchemaAnnotationsWithOAS31() throws Exception {
109+
public void testExplicitSchemaAnnotationsWithOAS31() {
107110
final ModelResolver modelResolver = new ModelResolver(Json31.mapper());
108111
Configuration configuration = new Configuration();
109112
configuration.setOpenAPI31(true);
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
package io.swagger.v3.core.issues;
2+
3+
import com.fasterxml.jackson.databind.JsonNode;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import io.swagger.v3.core.converter.ModelConverters;
6+
import io.swagger.v3.core.converter.ResolvedSchema;
7+
import io.swagger.v3.core.util.Json;
8+
import io.swagger.v3.core.util.Json31;
9+
import io.swagger.v3.core.util.ResourceUtils;
10+
import org.testng.annotations.Test;
11+
12+
import javax.annotation.Nullable;
13+
import java.io.IOException;
14+
import java.util.List;
15+
16+
import static org.testng.Assert.assertEquals;
17+
18+
/**
19+
* Reproduces GitHub Issue #5077
20+
* Issue using Nullable annotation for OAS 3.1
21+
*
22+
* <p>Tests that @Nullable annotation does not affect the item in a list:
23+
*
24+
* <p>Note: This test uses javax.annotation.Nullable which is automatically transformed to
25+
* jakarta.annotation.Nullable in the swagger-core-jakarta module via the Eclipse Transformer.
26+
*
27+
*/
28+
public class Issue5077Test {
29+
30+
@Test
31+
public void testOAS31() throws IOException {
32+
ResolvedSchema schema = ModelConverters.getInstance(true)
33+
.readAllAsResolvedSchema(ModelWithObjectAndList.class);
34+
35+
String expectedJson = ResourceUtils.loadClassResource(getClass(), "specFiles/NullableFieldsOAS31.json");
36+
String actualJson = Json31.pretty(schema);
37+
ObjectMapper mapper = new ObjectMapper();
38+
JsonNode expectedNode = mapper.readTree(expectedJson);
39+
JsonNode actualNode = mapper.readTree(actualJson);
40+
assertEquals(actualNode, expectedNode);
41+
}
42+
43+
@Test
44+
public void testOAS30() throws IOException {
45+
ResolvedSchema schema = ModelConverters.getInstance()
46+
.readAllAsResolvedSchema(ModelWithObjectAndList.class);
47+
48+
String expectedJson = ResourceUtils.loadClassResource(getClass(), "specFiles/NullableFieldsOAS30.json");
49+
String actualJson = Json.pretty(schema);
50+
ObjectMapper mapper = new ObjectMapper();
51+
JsonNode expectedNode = mapper.readTree(expectedJson);
52+
JsonNode actualNode = mapper.readTree(actualJson);
53+
assertEquals(actualNode, expectedNode);
54+
}
55+
56+
public static class ModelWithObjectAndList {
57+
58+
@Nullable
59+
private String nullableString;
60+
61+
private String requiredString;
62+
63+
@Nullable
64+
private Model nullableModel;
65+
66+
@Nullable
67+
private List<String> strings;
68+
69+
@Nullable
70+
private List<Model> models;
71+
72+
public String getNullableString() {
73+
return nullableString;
74+
}
75+
76+
public void setNullableString(String nullableString) {
77+
this.nullableString = nullableString;
78+
}
79+
80+
public String getRequiredString() {
81+
return requiredString;
82+
}
83+
84+
public void setRequiredString(String requiredString) {
85+
this.requiredString = requiredString;
86+
}
87+
88+
public Model getNullableModel() {
89+
return nullableModel;
90+
}
91+
92+
public void setNullableModel(Model model) {
93+
this.nullableModel = model;
94+
}
95+
96+
public List<Model> getModels() {
97+
return models;
98+
}
99+
100+
public void setModels(List<Model> models) {
101+
this.models = models;
102+
}
103+
104+
@Nullable
105+
public List<String> getStrings() {
106+
return strings;
107+
}
108+
109+
public void setStrings(@Nullable List<String> strings) {
110+
this.strings = strings;
111+
}
112+
}
113+
114+
public static class Model {
115+
private String field;
116+
117+
public String getField() {
118+
return field;
119+
}
120+
121+
public void setField(String field) {
122+
this.field = field;
123+
}
124+
}
125+
126+
}
Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"schema" : {
3-
"description" : "The holder",
3+
"type" : "object",
44
"properties" : {
55
"name" : {
66
"type" : "string"
@@ -9,34 +9,36 @@
99
"type" : "string"
1010
},
1111
"baseArray" : {
12+
"minItems" : 0,
13+
"uniqueItems" : true,
1214
"type" : "array",
1315
"description" : "Thingy",
1416
"items" : {
1517
"$ref" : "#/components/schemas/Base"
16-
},
17-
"minItems" : 0,
18-
"uniqueItems" : true
18+
}
1919
}
20-
}
20+
},
21+
"description" : "The holder"
2122
},
2223
"referencedSchemas" : {
2324
"Base" : {
25+
"type" : "object",
26+
"properties" : {
27+
"name" : {
28+
"type" : "string"
29+
}
30+
},
2431
"description" : "Stuff",
2532
"discriminator" : {
2633
"propertyName" : "name",
2734
"mapping" : {
2835
"a" : "#/components/schemas/SubA",
2936
"b" : "#/components/schemas/SubB"
3037
}
31-
},
32-
"properties" : {
33-
"name" : {
34-
"type" : "string"
35-
}
3638
}
3739
},
3840
"Holder" : {
39-
"description" : "The holder",
41+
"type" : "object",
4042
"properties" : {
4143
"name" : {
4244
"type" : "string"
@@ -45,18 +47,19 @@
4547
"type" : "string"
4648
},
4749
"baseArray" : {
50+
"minItems" : 0,
51+
"uniqueItems" : true,
4852
"type" : "array",
4953
"description" : "Thingy",
5054
"items" : {
5155
"$ref" : "#/components/schemas/Base"
52-
},
53-
"minItems" : 0,
54-
"uniqueItems" : true
56+
}
5557
}
56-
}
58+
},
59+
"description" : "The holder"
5760
},
5861
"SubA" : {
59-
"description" : "The SubA class",
62+
"type" : "object",
6063
"properties" : {
6164
"name" : {
6265
"type" : "string"
@@ -65,18 +68,20 @@
6568
"type" : "integer",
6669
"format" : "int64"
6770
}
68-
}
71+
},
72+
"description" : "The SubA class"
6973
},
7074
"SubB" : {
71-
"description" : "The SubB class",
75+
"type" : "object",
7276
"properties" : {
7377
"name" : {
7478
"type" : "string"
7579
},
7680
"friend" : {
7781
"type" : "string"
7882
}
79-
}
83+
},
84+
"description" : "The SubB class"
8085
}
8186
}
8287
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"schema" : {
3+
"type" : "object",
4+
"properties" : {
5+
"nullableString" : {
6+
"type" : "string",
7+
"nullable" : true
8+
},
9+
"requiredString" : {
10+
"type" : "string"
11+
},
12+
"nullableModel" : {
13+
"$ref" : "#/components/schemas/Model"
14+
},
15+
"strings" : {
16+
"type" : "array",
17+
"nullable" : true,
18+
"items" : {
19+
"type" : "string"
20+
}
21+
},
22+
"models" : {
23+
"type" : "array",
24+
"nullable" : true,
25+
"items" : {
26+
"$ref" : "#/components/schemas/Model"
27+
}
28+
}
29+
}
30+
},
31+
"referencedSchemas" : {
32+
"Model" : {
33+
"type" : "object",
34+
"properties" : {
35+
"field" : {
36+
"type" : "string"
37+
}
38+
}
39+
},
40+
"ModelWithObjectAndList" : {
41+
"type" : "object",
42+
"properties" : {
43+
"nullableString" : {
44+
"type" : "string",
45+
"nullable" : true
46+
},
47+
"requiredString" : {
48+
"type" : "string"
49+
},
50+
"nullableModel" : {
51+
"$ref" : "#/components/schemas/Model"
52+
},
53+
"strings" : {
54+
"type" : "array",
55+
"nullable" : true,
56+
"items" : {
57+
"type" : "string"
58+
}
59+
},
60+
"models" : {
61+
"type" : "array",
62+
"nullable" : true,
63+
"items" : {
64+
"$ref" : "#/components/schemas/Model"
65+
}
66+
}
67+
}
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)