Skip to content

Commit afe3054

Browse files
committed
Please add OpenAPI 3.1 supports. Fixes #1181
1 parent 5d4e485 commit afe3054

File tree

1,521 files changed

+40710
-28874
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,521 files changed

+40710
-28874
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
/*
22
*
33
* *
4-
* * * Copyright 2019-2020 the original author or authors.
54
* * *
6-
* * * Licensed under the Apache License, Version 2.0 (the "License");
7-
* * * you may not use this file except in compliance with the License.
8-
* * * You may obtain a copy of the License at
5+
* * * * Copyright 2019-2022 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
918
* * *
10-
* * * https://www.apache.org/licenses/LICENSE-2.0
11-
* * *
12-
* * * Unless required by applicable law or agreed to in writing, software
13-
* * * distributed under the License is distributed on an "AS IS" BASIS,
14-
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
* * * See the License for the specific language governing permissions and
16-
* * * limitations under the License.
1719
* *
1820
*
1921
*/
@@ -52,9 +54,7 @@
5254
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
5355
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature;
5456
import io.swagger.v3.core.filter.SpecFilter;
55-
import io.swagger.v3.core.util.Json;
5657
import io.swagger.v3.core.util.ReflectionUtils;
57-
import io.swagger.v3.core.util.Yaml;
5858
import io.swagger.v3.oas.annotations.Hidden;
5959
import io.swagger.v3.oas.annotations.callbacks.Callback;
6060
import io.swagger.v3.oas.annotations.enums.ParameterIn;
@@ -74,14 +74,17 @@
7474
import org.slf4j.Logger;
7575
import org.slf4j.LoggerFactory;
7676
import org.springdoc.api.mixins.SortedOpenAPIMixin;
77+
import org.springdoc.api.mixins.SortedOpenAPIMixin31;
7778
import org.springdoc.api.mixins.SortedSchemaMixin;
79+
import org.springdoc.api.mixins.SortedSchemaMixin31;
7880
import org.springdoc.core.AbstractRequestService;
7981
import org.springdoc.core.GenericParameterService;
8082
import org.springdoc.core.GenericResponseService;
8183
import org.springdoc.core.MethodAttributes;
8284
import org.springdoc.core.OpenAPIService;
8385
import org.springdoc.core.OperationService;
8486
import org.springdoc.core.SpringDocConfigProperties;
87+
import org.springdoc.core.SpringDocConfigProperties.ApiDocs.OpenApiVersion;
8588
import org.springdoc.core.SpringDocConfigProperties.GroupConfig;
8689
import org.springdoc.core.SpringDocProviders;
8790
import org.springdoc.core.annotations.RouterOperations;
@@ -315,6 +318,8 @@ protected synchronized OpenAPI getOpenApi(Locale locale) {
315318
Map<String, Object> findControllerAdvice = openAPIService.getControllerAdviceMap();
316319
// calculate generic responses
317320
openApi = openAPIService.getCalculatedOpenAPI();
321+
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion())
322+
openApi.openapi(OpenApiVersion.OPENAPI_3_1.getVersion());
318323
if (springDocConfigProperties.isDefaultOverrideWithGenericResponse()) {
319324
if (!CollectionUtils.isEmpty(mappingsMap))
320325
findControllerAdvice.putAll(mappingsMap);
@@ -341,8 +346,8 @@ protected synchronized OpenAPI getOpenApi(Locale locale) {
341346
List<Server> servers = openApi.getServers();
342347
List<Server> serversCopy = null;
343348
try {
344-
serversCopy = Json.mapper()
345-
.readValue(Json.mapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
349+
serversCopy = springDocProviders.jsonMapper()
350+
.readValue(springDocProviders.jsonMapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
346351
}
347352
catch (JsonProcessingException e) {
348353
LOGGER.warn("Json Processing Exception occurred: {}", e.getMessage());
@@ -610,7 +615,7 @@ protected void calculatePath(RouterOperation routerOperation, Locale locale) {
610615
* @param locale the locale
611616
*/
612617
protected void calculatePath(HandlerMethod handlerMethod, String operationPath,
613-
Set<RequestMethod> requestMethods,String[] consumes, String[] produces, String[] headers, Locale locale) {
618+
Set<RequestMethod> requestMethods, String[] consumes, String[] produces, String[] headers, Locale locale) {
614619
this.calculatePath(handlerMethod, new RouterOperation(operationPath, requestMethods.toArray(new RequestMethod[requestMethods.size()]), consumes, produces, headers), locale);
615620
}
616621

@@ -837,7 +842,7 @@ protected Set<RequestMethod> getDefaultAllowedHttpMethods() {
837842
* @return the operation
838843
*/
839844
protected Operation customiseOperation(Operation operation, HandlerMethod handlerMethod) {
840-
if(operationCustomizers.isPresent()){
845+
if (operationCustomizers.isPresent()) {
841846
List<OperationCustomizer> operationCustomizerList = operationCustomizers.get();
842847
for (OperationCustomizer operationCustomizer : operationCustomizerList)
843848
operation = operationCustomizer.customize(operation, handlerMethod);
@@ -1172,7 +1177,7 @@ protected void initOpenAPIBuilder(Locale locale) {
11721177
*/
11731178
protected String writeYamlValue(OpenAPI openAPI) throws JsonProcessingException {
11741179
String result;
1175-
ObjectMapper objectMapper = Yaml.mapper();
1180+
ObjectMapper objectMapper = springDocProviders.yamlMapper();
11761181
if (springDocConfigProperties.isWriterWithOrderByKeys())
11771182
sortOutput(objectMapper);
11781183
YAMLFactory factory = (YAMLFactory) objectMapper.getFactory();
@@ -1243,7 +1248,7 @@ protected boolean isActuatorRestController(String operationPath, HandlerMethod h
12431248
*/
12441249
protected String writeJsonValue(OpenAPI openAPI) throws JsonProcessingException {
12451250
String result;
1246-
ObjectMapper objectMapper = Json.mapper();
1251+
ObjectMapper objectMapper = springDocProviders.jsonMapper();
12471252
if (springDocConfigProperties.isWriterWithOrderByKeys())
12481253
sortOutput(objectMapper);
12491254
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
@@ -1322,8 +1327,13 @@ enum ConditionType {
13221327
private void sortOutput(ObjectMapper objectMapper) {
13231328
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
13241329
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
1325-
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin.class);
1326-
objectMapper.addMixIn(Schema.class, SortedSchemaMixin.class);
1330+
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion()){
1331+
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin31.class);
1332+
objectMapper.addMixIn(Schema.class, SortedSchemaMixin31.class);
1333+
} else {
1334+
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin.class);
1335+
objectMapper.addMixIn(Schema.class, SortedSchemaMixin.class);
1336+
}
13271337
}
13281338

13291339
/**
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * * Copyright 2019-2022 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
18+
* * *
19+
* *
20+
*
21+
*/
22+
23+
package org.springdoc.api.mixins;
24+
25+
import java.util.Map;
26+
27+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
28+
import com.fasterxml.jackson.annotation.JsonAnySetter;
29+
import com.fasterxml.jackson.annotation.JsonInclude;
30+
import com.fasterxml.jackson.annotation.JsonInclude.Include;
31+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
32+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
33+
import io.swagger.v3.core.jackson.PathsSerializer;
34+
import io.swagger.v3.oas.models.Paths;
35+
36+
/**
37+
* @author bnasslashen
38+
*/
39+
@JsonPropertyOrder(value = {"openapi", "info", "externalDocs", "servers", "security", "tags", "paths", "components", "webhooks"}, alphabetic = true)
40+
public interface SortedOpenAPIMixin31 {
41+
42+
@JsonAnyGetter
43+
@JsonInclude(value = Include.ALWAYS)
44+
@JsonPropertyOrder(alphabetic = true)
45+
Map<String, Object> getExtensions();
46+
47+
@JsonAnySetter
48+
void addExtension(String name, Object value);
49+
50+
@JsonSerialize(using = PathsSerializer.class)
51+
Paths getPaths();
52+
53+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * * Copyright 2019-2022 the original author or authors.
6+
* * * *
7+
* * * * Licensed under the Apache License, Version 2.0 (the "License");
8+
* * * * you may not use this file except in compliance with the License.
9+
* * * * You may obtain a copy of the License at
10+
* * * *
11+
* * * * https://www.apache.org/licenses/LICENSE-2.0
12+
* * * *
13+
* * * * Unless required by applicable law or agreed to in writing, software
14+
* * * * distributed under the License is distributed on an "AS IS" BASIS,
15+
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* * * * See the License for the specific language governing permissions and
17+
* * * * limitations under the License.
18+
* * *
19+
* *
20+
*
21+
*/
22+
23+
package org.springdoc.api.mixins;
24+
25+
import java.math.BigDecimal;
26+
import java.util.Map;
27+
import java.util.Set;
28+
29+
import com.fasterxml.jackson.annotation.JsonAnyGetter;
30+
import com.fasterxml.jackson.annotation.JsonAnySetter;
31+
import com.fasterxml.jackson.annotation.JsonIgnore;
32+
import com.fasterxml.jackson.annotation.JsonInclude;
33+
import com.fasterxml.jackson.annotation.JsonProperty;
34+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
35+
36+
/**
37+
* @author bnasslashen
38+
*/
39+
@JsonPropertyOrder(value = {"type", "format"}, alphabetic = true)
40+
public interface SortedSchemaMixin31 {
41+
42+
@JsonAnyGetter
43+
@JsonPropertyOrder(alphabetic = true)
44+
Map<String, Object> getExtensions();
45+
46+
@JsonIgnore
47+
Map<String, Object> getJsonSchema();
48+
49+
@JsonIgnore
50+
Boolean getNullable();
51+
52+
@JsonIgnore
53+
Boolean getExclusiveMinimum();
54+
55+
@JsonIgnore
56+
Boolean getExclusiveMaximum();
57+
58+
@JsonProperty("exclusiveMinimum")
59+
BigDecimal getExclusiveMinimumValue();
60+
61+
@JsonProperty("exclusiveMaximum")
62+
BigDecimal getExclusiveMaximumValue();
63+
64+
@JsonIgnore
65+
String getType();
66+
67+
@JsonProperty("type")
68+
Set<String> getTypes();
69+
70+
@JsonAnySetter
71+
void addExtension(String name, Object value);
72+
73+
@JsonIgnore
74+
boolean getExampleSetFlag();
75+
76+
@JsonInclude(JsonInclude.Include.CUSTOM)
77+
Object getExample();
78+
79+
@JsonIgnore
80+
Object getJsonSchemaImpl();
81+
82+
}

springdoc-openapi-common/src/main/java/org/springdoc/core/GenericParameterService.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
import com.fasterxml.jackson.annotation.JsonView;
3636
import io.swagger.v3.core.util.AnnotationsUtils;
37-
import io.swagger.v3.core.util.Json;
3837
import io.swagger.v3.core.util.PrimitiveType;
3938
import io.swagger.v3.oas.annotations.enums.Explode;
4039
import io.swagger.v3.oas.annotations.media.ExampleObject;
@@ -50,6 +49,7 @@
5049
import org.slf4j.Logger;
5150
import org.slf4j.LoggerFactory;
5251
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
52+
import org.springdoc.core.providers.ObjectMapperProvider;
5353
import org.springdoc.core.providers.WebConversionServiceProvider;
5454

5555
import org.springframework.beans.factory.config.BeanExpressionContext;
@@ -110,18 +110,26 @@ public class GenericParameterService {
110110
*/
111111
private ConfigurableBeanFactory configurableBeanFactory;
112112

113+
/**
114+
* The Object mapper provider.
115+
*/
116+
private final ObjectMapperProvider objectMapperProvider;
117+
113118
/**
114119
* Instantiates a new Generic parameter builder.
115120
* @param propertyResolverUtils the property resolver utils
116121
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
117-
* @param optionalWebConversionServiceProvider
122+
* @param optionalWebConversionServiceProvider the optional web conversion service provider
123+
* @param objectMapperProvider the object mapper provider
118124
*/
119-
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer, Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider) {
125+
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
126+
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
120127
this.propertyResolverUtils = propertyResolverUtils;
121128
this.optionalDelegatingMethodParameterCustomizer = optionalDelegatingMethodParameterCustomizer;
122129
this.optionalWebConversionServiceProvider = optionalWebConversionServiceProvider;
123130
this.configurableBeanFactory = propertyResolverUtils.getFactory();
124131
this.expressionContext = (configurableBeanFactory != null ? new BeanExpressionContext(configurableBeanFactory, new RequestScope()) : null);
132+
this.objectMapperProvider = objectMapperProvider;
125133
}
126134

127135
/**
@@ -232,7 +240,7 @@ public Parameter buildParameterFromDoc(io.swagger.v3.oas.annotations.Parameter p
232240
parameter.setIn(parameterDoc.in().toString());
233241
if (StringUtils.isNotBlank(parameterDoc.example())) {
234242
try {
235-
parameter.setExample(Json.mapper().readTree(parameterDoc.example()));
243+
parameter.setExample(objectMapperProvider.jsonMapper().readTree(parameterDoc.example()));
236244
}
237245
catch (IOException e) {
238246
parameter.setExample(parameterDoc.example());
@@ -294,7 +302,7 @@ private void setSchema(io.swagger.v3.oas.annotations.Parameter parameterDoc, Com
294302
schema = AnnotationsUtils.getSchema(parameterDoc.schema(), parameterDoc.array(), true, parameterDoc.array().schema().implementation(), components, jsonView).orElse(null);
295303
// default value not set by swagger-core for array !
296304
if (schema != null) {
297-
Object defaultValue = SpringDocAnnotationsUtils.resolveDefaultValue(parameterDoc.array().arraySchema().defaultValue());
305+
Object defaultValue = SpringDocAnnotationsUtils.resolveDefaultValue(parameterDoc.array().arraySchema().defaultValue(), objectMapperProvider.jsonMapper());
298306
schema.setDefault(defaultValue);
299307
}
300308
}
@@ -524,6 +532,8 @@ public Optional<WebConversionServiceProvider> getOptionalWebConversionServicePro
524532
/**
525533
* Resolve the given annotation-specified value,
526534
* potentially containing placeholders and expressions.
535+
* @param value the value
536+
* @return the object
527537
*/
528538
public Object resolveEmbeddedValuesAndExpressions(String value) {
529539
if (this.configurableBeanFactory == null || this.expressionContext == null) {

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocAnnotationsUtils.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232

3333
import com.fasterxml.jackson.annotation.JsonIgnore;
3434
import com.fasterxml.jackson.annotation.JsonView;
35+
import com.fasterxml.jackson.databind.ObjectMapper;
3536
import io.swagger.v3.core.converter.AnnotatedType;
3637
import io.swagger.v3.core.converter.ModelConverters;
3738
import io.swagger.v3.core.converter.ResolvedSchema;
3839
import io.swagger.v3.core.util.AnnotationsUtils;
39-
import io.swagger.v3.core.util.Json;
4040
import io.swagger.v3.oas.annotations.Hidden;
4141
import io.swagger.v3.oas.annotations.media.ExampleObject;
4242
import io.swagger.v3.oas.models.Components;
@@ -376,11 +376,11 @@ private static boolean isArray(io.swagger.v3.oas.annotations.media.Content annot
376376
return isArray;
377377
}
378378

379-
public static Object resolveDefaultValue(String defaultValueStr) {
379+
public static Object resolveDefaultValue(String defaultValueStr, ObjectMapper objectMapper) {
380380
Object defaultValue = null;
381381
if (StringUtils.isNotEmpty(defaultValueStr)) {
382382
try {
383-
defaultValue = Json.mapper().readTree(defaultValueStr);
383+
defaultValue = objectMapper.readTree(defaultValueStr);
384384
}
385385
catch (IOException e) {
386386
defaultValue = defaultValueStr;

0 commit comments

Comments
 (0)