org.springdoc.core.OperationBuilder Maven / Gradle / Ivy
package org.springdoc.core;
import static org.springdoc.core.Constants.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import com.fasterxml.jackson.annotation.JsonView;
import io.swagger.v3.core.util.AnnotationsUtils;
import io.swagger.v3.core.util.ReflectionUtils;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.links.Link;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
import io.swagger.v3.oas.models.security.SecurityRequirement;
@Component
public class OperationBuilder {
private ParameterBuilder parameterBuilder;
private RequestBodyBuilder requestBodyBuilder;
private SecurityParser securityParser;
public OperationBuilder(ParameterBuilder parameterBuilder, RequestBodyBuilder requestBodyBuilder,
SecurityParser securityParser) {
super();
this.parameterBuilder = parameterBuilder;
this.requestBodyBuilder = requestBodyBuilder;
this.securityParser = securityParser;
}
public OpenAPI parse(Components components, io.swagger.v3.oas.annotations.Operation apiOperation,
Operation operation, OpenAPI openAPI, MediaAttributes mediaAttributes) {
if (StringUtils.isNotBlank(apiOperation.summary())) {
operation.setSummary(apiOperation.summary());
}
if (StringUtils.isNotBlank(apiOperation.description())) {
operation.setDescription(apiOperation.description());
}
if (StringUtils.isNotBlank(apiOperation.operationId())) {
operation.setOperationId(getOperationId(apiOperation.operationId(), openAPI));
}
if (apiOperation.deprecated()) {
operation.setDeprecated(apiOperation.deprecated());
}
buildTags(apiOperation, operation);
if (operation.getExternalDocs() == null) { // if not set in root annotation
AnnotationsUtils.getExternalDocumentation(apiOperation.externalDocs())
.ifPresent(operation::setExternalDocs);
}
// servers
AnnotationsUtils.getServers(apiOperation.servers())
.ifPresent(servers -> servers.forEach(operation::addServersItem));
// build parameters
for (io.swagger.v3.oas.annotations.Parameter parameterDoc : apiOperation.parameters()) {
Parameter parameter = parameterBuilder.buildParameterFromDoc(parameterDoc, components);
operation.addParametersItem(parameter);
}
// RequestBody in Operation
requestBodyBuilder.buildRequestBodyFromDoc(apiOperation.requestBody(), mediaAttributes.getClassConsumes(),
mediaAttributes.getMethodConsumes(), components, null).ifPresent(operation::setRequestBody);
// build response
buildResponse(components, apiOperation, operation, mediaAttributes);
// security
Optional> requirementsObject = securityParser
.getSecurityRequirements(apiOperation.security());
if (requirementsObject.isPresent()) {
requirementsObject.get().stream()
.filter(r -> operation.getSecurity() == null || !operation.getSecurity().contains(r))
.forEach(operation::addSecurityItem);
}
// Extensions in Operation
buildExtensions(apiOperation, operation);
return openAPI;
}
public boolean isHidden(Method method) {
io.swagger.v3.oas.annotations.Operation apiOperation = ReflectionUtils.getAnnotation(method,
io.swagger.v3.oas.annotations.Operation.class);
return (apiOperation != null && (apiOperation.hidden()))
|| (ReflectionUtils.getAnnotation(method, Hidden.class) != null);
}
private void buildExtensions(io.swagger.v3.oas.annotations.Operation apiOperation, Operation operation) {
if (apiOperation.extensions().length > 0) {
Map extensions = AnnotationsUtils.getExtensions(apiOperation.extensions());
for (Map.Entry entry : extensions.entrySet()) {
operation.addExtension(entry.getKey(), entry.getValue());
}
}
}
private void buildTags(io.swagger.v3.oas.annotations.Operation apiOperation, Operation operation) {
Optional> mlist = getStringListFromStringArray(apiOperation.tags());
if (mlist.isPresent()) {
List tags = mlist.get().stream()
.filter(t -> operation.getTags() == null
|| (operation.getTags() != null && !operation.getTags().contains(t)))
.collect(Collectors.toList());
for (String tagsItem : tags) {
operation.addTagsItem(tagsItem);
}
}
}
private String getOperationId(String operationId, OpenAPI openAPI) {
boolean operationIdUsed = existOperationId(operationId, openAPI);
String operationIdToFind = null;
int counter = 0;
while (operationIdUsed) {
operationIdToFind = String.format("%s_%d", operationId, ++counter);
operationIdUsed = existOperationId(operationIdToFind, openAPI);
}
if (operationIdToFind != null) {
operationId = operationIdToFind;
}
return operationId;
}
private boolean existOperationId(String operationId, OpenAPI openAPI) {
if (openAPI == null) {
return false;
}
if (openAPI.getPaths() == null || openAPI.getPaths().isEmpty()) {
return false;
}
for (PathItem path : openAPI.getPaths().values()) {
Set pathOperationIds = extractOperationIdFromPathItem(path);
if (pathOperationIds.contains(operationId)) {
return true;
}
}
return false;
}
private Set extractOperationIdFromPathItem(PathItem path) {
Set ids = new HashSet<>();
if (path.getGet() != null && StringUtils.isNotBlank(path.getGet().getOperationId())) {
ids.add(path.getGet().getOperationId());
}
if (path.getPost() != null && StringUtils.isNotBlank(path.getPost().getOperationId())) {
ids.add(path.getPost().getOperationId());
}
if (path.getPut() != null && StringUtils.isNotBlank(path.getPut().getOperationId())) {
ids.add(path.getPut().getOperationId());
}
if (path.getDelete() != null && StringUtils.isNotBlank(path.getDelete().getOperationId())) {
ids.add(path.getDelete().getOperationId());
}
if (path.getOptions() != null && StringUtils.isNotBlank(path.getOptions().getOperationId())) {
ids.add(path.getOptions().getOperationId());
}
if (path.getHead() != null && StringUtils.isNotBlank(path.getHead().getOperationId())) {
ids.add(path.getHead().getOperationId());
}
if (path.getPatch() != null && StringUtils.isNotBlank(path.getPatch().getOperationId())) {
ids.add(path.getPatch().getOperationId());
}
return ids;
}
private Optional getApiResponses(
final io.swagger.v3.oas.annotations.responses.ApiResponse[] responses, String[] classProduces,
String[] methodProduces, Components components, JsonView jsonViewAnnotation) {
ApiResponses apiResponsesObject = new ApiResponses();
for (io.swagger.v3.oas.annotations.responses.ApiResponse response : responses) {
ApiResponse apiResponseObject = new ApiResponse();
if (StringUtils.isNotBlank(response.ref())) {
setRef(apiResponsesObject, response, apiResponseObject);
continue;
}
setDescription(response, apiResponseObject);
setExtensions(response, apiResponseObject);
org.springdoc.core.SpringDocAnnotationsUtils.getContent(response.content(),
classProduces == null ? new String[0] : classProduces,
methodProduces == null ? new String[0] : methodProduces, null, components, jsonViewAnnotation)
.ifPresent(apiResponseObject::content);
AnnotationsUtils.getHeaders(response.headers(), jsonViewAnnotation).ifPresent(apiResponseObject::headers);
// Make schema as string if empty
calculateHeader(apiResponseObject);
if (isResponseObject(apiResponseObject)) {
setLinks(response, apiResponseObject);
if (StringUtils.isNotBlank(response.responseCode())) {
apiResponsesObject.addApiResponse(response.responseCode(), apiResponseObject);
} else {
apiResponsesObject._default(apiResponseObject);
}
}
}
return Optional.of(apiResponsesObject);
}
private boolean isResponseObject(ApiResponse apiResponseObject) {
return StringUtils.isNotBlank(apiResponseObject.getDescription()) || apiResponseObject.getContent() != null
|| apiResponseObject.getHeaders() != null;
}
private void setLinks(io.swagger.v3.oas.annotations.responses.ApiResponse response, ApiResponse apiResponseObject) {
Map links = AnnotationsUtils.getLinks(response.links());
if (links.size() > 0) {
apiResponseObject.setLinks(links);
}
}
private void setDescription(io.swagger.v3.oas.annotations.responses.ApiResponse response,
ApiResponse apiResponseObject) {
if (StringUtils.isNotBlank(response.description())) {
apiResponseObject.setDescription(response.description());
} else {
apiResponseObject.setDescription(DEFAULT_DESCRIPTION);
}
}
private void calculateHeader(ApiResponse apiResponseObject) {
Map headers = apiResponseObject.getHeaders();
if (!CollectionUtils.isEmpty(headers)) {
for (Map.Entry entry : headers.entrySet()) {
Header header = entry.getValue();
if (header.getSchema() == null) {
Schema> schema = AnnotationsUtils.resolveSchemaFromType(String.class, null, null);
header.setSchema(schema);
entry.setValue(header);
}
}
}
}
private void setRef(ApiResponses apiResponsesObject, io.swagger.v3.oas.annotations.responses.ApiResponse response,
ApiResponse apiResponseObject) {
apiResponseObject.set$ref(response.ref());
if (StringUtils.isNotBlank(response.responseCode())) {
apiResponsesObject.addApiResponse(response.responseCode(), apiResponseObject);
} else {
apiResponsesObject._default(apiResponseObject);
}
}
private void setExtensions(io.swagger.v3.oas.annotations.responses.ApiResponse response,
ApiResponse apiResponseObject) {
if (response.extensions().length > 0) {
Map extensions = AnnotationsUtils.getExtensions(response.extensions());
for (Map.Entry entry : extensions.entrySet()) {
apiResponseObject.addExtension(entry.getKey(), entry.getValue());
}
}
}
private void buildResponse(Components components, io.swagger.v3.oas.annotations.Operation apiOperation,
Operation operation, MediaAttributes mediaAttributes) {
getApiResponses(apiOperation.responses(), mediaAttributes.getClassProduces(),
mediaAttributes.getMethodProduces(), components, null).ifPresent(responses -> {
if (operation.getResponses() == null) {
operation.setResponses(responses);
} else {
responses.forEach(operation.getResponses()::addApiResponse);
}
});
}
private Optional> getStringListFromStringArray(String[] array) {
if (array == null) {
return Optional.empty();
}
List list = new ArrayList<>();
boolean isEmpty = true;
for (String value : array) {
if (StringUtils.isNotBlank(value)) {
isEmpty = false;
}
list.add(value);
}
if (isEmpty) {
return Optional.empty();
}
return Optional.of(list);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy