Skip to content

Commit

Permalink
Please add OpenAPI 3.1 supports. Fixes #1181
Browse files Browse the repository at this point in the history
  • Loading branch information
bnasslahsen committed Apr 23, 2022
1 parent 5d4e485 commit afe3054
Show file tree
Hide file tree
Showing 1,521 changed files with 40,710 additions and 28,874 deletions.
@@ -1,19 +1,21 @@
/*
*
* *
* * * Copyright 2019-2020 the original author or authors.
* * *
* * * Licensed under the Apache License, Version 2.0 (the "License");
* * * you may not use this file except in compliance with the License.
* * * You may obtain a copy of the License at
* * * * Copyright 2019-2022 the original author or authors.
* * * *
* * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * you may not use this file except in compliance with the License.
* * * * You may obtain a copy of the License at
* * * *
* * * * https://www.apache.org/licenses/LICENSE-2.0
* * * *
* * * * Unless required by applicable law or agreed to in writing, software
* * * * distributed under the License is distributed on an "AS IS" BASIS,
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * * * See the License for the specific language governing permissions and
* * * * limitations under the License.
* * *
* * * https://www.apache.org/licenses/LICENSE-2.0
* * *
* * * Unless required by applicable law or agreed to in writing, software
* * * distributed under the License is distributed on an "AS IS" BASIS,
* * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * * See the License for the specific language governing permissions and
* * * limitations under the License.
* *
*
*/
Expand Down Expand Up @@ -52,9 +54,7 @@
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature;
import io.swagger.v3.core.filter.SpecFilter;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.ReflectionUtils;
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.callbacks.Callback;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
Expand All @@ -74,14 +74,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.api.mixins.SortedOpenAPIMixin;
import org.springdoc.api.mixins.SortedOpenAPIMixin31;
import org.springdoc.api.mixins.SortedSchemaMixin;
import org.springdoc.api.mixins.SortedSchemaMixin31;
import org.springdoc.core.AbstractRequestService;
import org.springdoc.core.GenericParameterService;
import org.springdoc.core.GenericResponseService;
import org.springdoc.core.MethodAttributes;
import org.springdoc.core.OpenAPIService;
import org.springdoc.core.OperationService;
import org.springdoc.core.SpringDocConfigProperties;
import org.springdoc.core.SpringDocConfigProperties.ApiDocs.OpenApiVersion;
import org.springdoc.core.SpringDocConfigProperties.GroupConfig;
import org.springdoc.core.SpringDocProviders;
import org.springdoc.core.annotations.RouterOperations;
Expand Down Expand Up @@ -315,6 +318,8 @@ protected synchronized OpenAPI getOpenApi(Locale locale) {
Map<String, Object> findControllerAdvice = openAPIService.getControllerAdviceMap();
// calculate generic responses
openApi = openAPIService.getCalculatedOpenAPI();
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion())
openApi.openapi(OpenApiVersion.OPENAPI_3_1.getVersion());
if (springDocConfigProperties.isDefaultOverrideWithGenericResponse()) {
if (!CollectionUtils.isEmpty(mappingsMap))
findControllerAdvice.putAll(mappingsMap);
Expand All @@ -341,8 +346,8 @@ protected synchronized OpenAPI getOpenApi(Locale locale) {
List<Server> servers = openApi.getServers();
List<Server> serversCopy = null;
try {
serversCopy = Json.mapper()
.readValue(Json.mapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
serversCopy = springDocProviders.jsonMapper()
.readValue(springDocProviders.jsonMapper().writeValueAsString(servers), new TypeReference<List<Server>>() {});
}
catch (JsonProcessingException e) {
LOGGER.warn("Json Processing Exception occurred: {}", e.getMessage());
Expand Down Expand Up @@ -610,7 +615,7 @@ protected void calculatePath(RouterOperation routerOperation, Locale locale) {
* @param locale the locale
*/
protected void calculatePath(HandlerMethod handlerMethod, String operationPath,
Set<RequestMethod> requestMethods,String[] consumes, String[] produces, String[] headers, Locale locale) {
Set<RequestMethod> requestMethods, String[] consumes, String[] produces, String[] headers, Locale locale) {
this.calculatePath(handlerMethod, new RouterOperation(operationPath, requestMethods.toArray(new RequestMethod[requestMethods.size()]), consumes, produces, headers), locale);
}

Expand Down Expand Up @@ -837,7 +842,7 @@ protected Set<RequestMethod> getDefaultAllowedHttpMethods() {
* @return the operation
*/
protected Operation customiseOperation(Operation operation, HandlerMethod handlerMethod) {
if(operationCustomizers.isPresent()){
if (operationCustomizers.isPresent()) {
List<OperationCustomizer> operationCustomizerList = operationCustomizers.get();
for (OperationCustomizer operationCustomizer : operationCustomizerList)
operation = operationCustomizer.customize(operation, handlerMethod);
Expand Down Expand Up @@ -1172,7 +1177,7 @@ protected void initOpenAPIBuilder(Locale locale) {
*/
protected String writeYamlValue(OpenAPI openAPI) throws JsonProcessingException {
String result;
ObjectMapper objectMapper = Yaml.mapper();
ObjectMapper objectMapper = springDocProviders.yamlMapper();
if (springDocConfigProperties.isWriterWithOrderByKeys())
sortOutput(objectMapper);
YAMLFactory factory = (YAMLFactory) objectMapper.getFactory();
Expand Down Expand Up @@ -1243,7 +1248,7 @@ protected boolean isActuatorRestController(String operationPath, HandlerMethod h
*/
protected String writeJsonValue(OpenAPI openAPI) throws JsonProcessingException {
String result;
ObjectMapper objectMapper = Json.mapper();
ObjectMapper objectMapper = springDocProviders.jsonMapper();
if (springDocConfigProperties.isWriterWithOrderByKeys())
sortOutput(objectMapper);
if (!springDocConfigProperties.isWriterWithDefaultPrettyPrinter())
Expand Down Expand Up @@ -1322,8 +1327,13 @@ enum ConditionType {
private void sortOutput(ObjectMapper objectMapper) {
objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin.class);
objectMapper.addMixIn(Schema.class, SortedSchemaMixin.class);
if (OpenApiVersion.OPENAPI_3_1 == springDocConfigProperties.getApiDocs().getVersion()){
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin31.class);
objectMapper.addMixIn(Schema.class, SortedSchemaMixin31.class);
} else {
objectMapper.addMixIn(OpenAPI.class, SortedOpenAPIMixin.class);
objectMapper.addMixIn(Schema.class, SortedSchemaMixin.class);
}
}

/**
Expand Down
@@ -0,0 +1,53 @@
/*
*
* *
* * *
* * * * Copyright 2019-2022 the original author or authors.
* * * *
* * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * you may not use this file except in compliance with the License.
* * * * You may obtain a copy of the License at
* * * *
* * * * https://www.apache.org/licenses/LICENSE-2.0
* * * *
* * * * Unless required by applicable law or agreed to in writing, software
* * * * distributed under the License is distributed on an "AS IS" BASIS,
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * * * See the License for the specific language governing permissions and
* * * * limitations under the License.
* * *
* *
*
*/

package org.springdoc.api.mixins;

import java.util.Map;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import io.swagger.v3.core.jackson.PathsSerializer;
import io.swagger.v3.oas.models.Paths;

/**
* @author bnasslashen
*/
@JsonPropertyOrder(value = {"openapi", "info", "externalDocs", "servers", "security", "tags", "paths", "components", "webhooks"}, alphabetic = true)
public interface SortedOpenAPIMixin31 {

@JsonAnyGetter
@JsonInclude(value = Include.ALWAYS)
@JsonPropertyOrder(alphabetic = true)
Map<String, Object> getExtensions();

@JsonAnySetter
void addExtension(String name, Object value);

@JsonSerialize(using = PathsSerializer.class)
Paths getPaths();

}
@@ -0,0 +1,82 @@
/*
*
* *
* * *
* * * * Copyright 2019-2022 the original author or authors.
* * * *
* * * * Licensed under the Apache License, Version 2.0 (the "License");
* * * * you may not use this file except in compliance with the License.
* * * * You may obtain a copy of the License at
* * * *
* * * * https://www.apache.org/licenses/LICENSE-2.0
* * * *
* * * * Unless required by applicable law or agreed to in writing, software
* * * * distributed under the License is distributed on an "AS IS" BASIS,
* * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * * * See the License for the specific language governing permissions and
* * * * limitations under the License.
* * *
* *
*
*/

package org.springdoc.api.mixins;

import java.math.BigDecimal;
import java.util.Map;
import java.util.Set;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

/**
* @author bnasslashen
*/
@JsonPropertyOrder(value = {"type", "format"}, alphabetic = true)
public interface SortedSchemaMixin31 {

@JsonAnyGetter
@JsonPropertyOrder(alphabetic = true)
Map<String, Object> getExtensions();

@JsonIgnore
Map<String, Object> getJsonSchema();

@JsonIgnore
Boolean getNullable();

@JsonIgnore
Boolean getExclusiveMinimum();

@JsonIgnore
Boolean getExclusiveMaximum();

@JsonProperty("exclusiveMinimum")
BigDecimal getExclusiveMinimumValue();

@JsonProperty("exclusiveMaximum")
BigDecimal getExclusiveMaximumValue();

@JsonIgnore
String getType();

@JsonProperty("type")
Set<String> getTypes();

@JsonAnySetter
void addExtension(String name, Object value);

@JsonIgnore
boolean getExampleSetFlag();

@JsonInclude(JsonInclude.Include.CUSTOM)
Object getExample();

@JsonIgnore
Object getJsonSchemaImpl();

}
Expand Up @@ -34,7 +34,6 @@

import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.core.util.PrimitiveType;
import io.swagger.v3.oas.annotations.enums.Explode;
import io.swagger.v3.oas.annotations.media.ExampleObject;
Expand All @@ -50,6 +49,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
import org.springdoc.core.providers.ObjectMapperProvider;
import org.springdoc.core.providers.WebConversionServiceProvider;

import org.springframework.beans.factory.config.BeanExpressionContext;
Expand Down Expand Up @@ -110,18 +110,26 @@ public class GenericParameterService {
*/
private ConfigurableBeanFactory configurableBeanFactory;

/**
* The Object mapper provider.
*/
private final ObjectMapperProvider objectMapperProvider;

/**
* Instantiates a new Generic parameter builder.
* @param propertyResolverUtils the property resolver utils
* @param optionalDelegatingMethodParameterCustomizer the optional delegating method parameter customizer
* @param optionalWebConversionServiceProvider
* @param optionalWebConversionServiceProvider the optional web conversion service provider
* @param objectMapperProvider the object mapper provider
*/
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer, Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider) {
public GenericParameterService(PropertyResolverUtils propertyResolverUtils, Optional<DelegatingMethodParameterCustomizer> optionalDelegatingMethodParameterCustomizer,
Optional<WebConversionServiceProvider> optionalWebConversionServiceProvider, ObjectMapperProvider objectMapperProvider) {
this.propertyResolverUtils = propertyResolverUtils;
this.optionalDelegatingMethodParameterCustomizer = optionalDelegatingMethodParameterCustomizer;
this.optionalWebConversionServiceProvider = optionalWebConversionServiceProvider;
this.configurableBeanFactory = propertyResolverUtils.getFactory();
this.expressionContext = (configurableBeanFactory != null ? new BeanExpressionContext(configurableBeanFactory, new RequestScope()) : null);
this.objectMapperProvider = objectMapperProvider;
}

/**
Expand Down Expand Up @@ -232,7 +240,7 @@ public Parameter buildParameterFromDoc(io.swagger.v3.oas.annotations.Parameter p
parameter.setIn(parameterDoc.in().toString());
if (StringUtils.isNotBlank(parameterDoc.example())) {
try {
parameter.setExample(Json.mapper().readTree(parameterDoc.example()));
parameter.setExample(objectMapperProvider.jsonMapper().readTree(parameterDoc.example()));
}
catch (IOException e) {
parameter.setExample(parameterDoc.example());
Expand Down Expand Up @@ -294,7 +302,7 @@ private void setSchema(io.swagger.v3.oas.annotations.Parameter parameterDoc, Com
schema = AnnotationsUtils.getSchema(parameterDoc.schema(), parameterDoc.array(), true, parameterDoc.array().schema().implementation(), components, jsonView).orElse(null);
// default value not set by swagger-core for array !
if (schema != null) {
Object defaultValue = SpringDocAnnotationsUtils.resolveDefaultValue(parameterDoc.array().arraySchema().defaultValue());
Object defaultValue = SpringDocAnnotationsUtils.resolveDefaultValue(parameterDoc.array().arraySchema().defaultValue(), objectMapperProvider.jsonMapper());
schema.setDefault(defaultValue);
}
}
Expand Down Expand Up @@ -524,6 +532,8 @@ public Optional<WebConversionServiceProvider> getOptionalWebConversionServicePro
/**
* Resolve the given annotation-specified value,
* potentially containing placeholders and expressions.
* @param value the value
* @return the object
*/
public Object resolveEmbeddedValuesAndExpressions(String value) {
if (this.configurableBeanFactory == null || this.expressionContext == null) {
Expand Down
Expand Up @@ -32,11 +32,11 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.core.converter.AnnotatedType;
import io.swagger.v3.core.converter.ModelConverters;
import io.swagger.v3.core.converter.ResolvedSchema;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.core.util.Json;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.models.Components;
Expand Down Expand Up @@ -376,11 +376,11 @@ private static boolean isArray(io.swagger.v3.oas.annotations.media.Content annot
return isArray;
}

public static Object resolveDefaultValue(String defaultValueStr) {
public static Object resolveDefaultValue(String defaultValueStr, ObjectMapper objectMapper) {
Object defaultValue = null;
if (StringUtils.isNotEmpty(defaultValueStr)) {
try {
defaultValue = Json.mapper().readTree(defaultValueStr);
defaultValue = objectMapper.readTree(defaultValueStr);
}
catch (IOException e) {
defaultValue = defaultValueStr;
Expand Down

0 comments on commit afe3054

Please sign in to comment.