Skip to content

Commit

Permalink
OpenAPI / Restore missing method. (#5752)
Browse files Browse the repository at this point in the history
Was mainly related to isRestController checking for non null RequestBody and also some controllers not listed in https://github.com/springdoc/springdoc-openapi/blob/master/springdoc-openapi-common/src/main/java/org/springdoc/core/OpenAPIService.java#L216-L218 (not sure why).
  • Loading branch information
fxprunayre committed Jul 6, 2021
1 parent aba4c31 commit 580a155
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 49 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -1508,7 +1508,7 @@
<spring.security.version>5.2.5.RELEASE</spring.security.version>
<spring.jpa.version>2.2.8.RELEASE</spring.jpa.version>
<springboot.version>2.2.2.RELEASE</springboot.version>
<springdoc.version>1.3.9</springdoc.version>
<springdoc.version>1.5.9</springdoc.version>

<metrics.version>2.1.1</metrics.version>
<maven.build.timestamp.format>yyyy-MM-dd'T'HH'\:'mm'\:'ssZ</maven.build.timestamp.format>
Expand Down
70 changes: 29 additions & 41 deletions services/src/main/java/org/fao/geonet/api/OpenApiController.java
Expand Up @@ -26,40 +26,26 @@
import io.swagger.v3.core.util.Yaml;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.OpenAPI;
import org.fao.geonet.ApplicationContextHolder;
import org.springdoc.api.AbstractOpenApiResource;
import org.springdoc.core.*;
import org.springdoc.core.customizers.OpenApiCustomiser;
import org.springdoc.core.customizers.OperationCustomizer;
import org.springdoc.core.visitor.AbstractRouterFunctionVisitor;
import org.springdoc.webmvc.api.ActuatorProvider;
import org.springdoc.webmvc.api.RouterFunctionProvider;
import org.springdoc.webmvc.core.RouterFunctionProvider;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

Expand Down Expand Up @@ -91,18 +77,19 @@ public class OpenApiController extends AbstractOpenApiResource {
private final Optional<RouterFunctionProvider> routerFunctionProvider;

@Autowired
public OpenApiController(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder requestBuilder,
GenericResponseBuilder responseBuilder, OperationBuilder operationParser,
RequestMappingInfoHandlerMapping requestMappingHandlerMapping,
Optional<ActuatorProvider> servletContextProvider,
Optional<List<OperationCustomizer>> operationCustomizers,
Optional<List<OpenApiCustomiser>> openApiCustomisers,
SpringDocConfigProperties springDocConfigProperties,
Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider,
Optional<RouterFunctionProvider> routerFunctionProvider) {
super(DEFAULT_GROUP_NAME, openAPIBuilder, requestBuilder, responseBuilder, operationParser, operationCustomizers, openApiCustomisers, springDocConfigProperties);

// springDocConfigProperties.setPathsToMatch(Arrays.asList(new String[]{"api/**"}));
public OpenApiController(ObjectFactory<OpenAPIService> openAPIBuilderObjectFactory,
AbstractRequestService requestBuilder,
GenericResponseService responseBuilder,
OperationService operationParser,
RequestMappingInfoHandlerMapping requestMappingHandlerMapping,
Optional<ActuatorProvider> servletContextProvider,
Optional<List<OperationCustomizer>> operationCustomizers,
Optional<List<OpenApiCustomiser>> openApiCustomisers,
SpringDocConfigProperties springDocConfigProperties,
Optional<ActuatorProvider> actuatorProvider,
Optional<SecurityOAuth2Provider> springSecurityOAuth2Provider,
Optional<RouterFunctionProvider> routerFunctionProvider) {
super(DEFAULT_GROUP_NAME, openAPIBuilderObjectFactory, requestBuilder, responseBuilder, operationParser, operationCustomizers, openApiCustomisers, springDocConfigProperties, actuatorProvider);
springDocConfigProperties.setPathsToExclude(Arrays.asList(new String[]{"/0.1/**"}));
springDocConfigProperties.setPackagesToScan(Arrays.asList(new String[]{
"org.fao.geonet.api",
Expand Down Expand Up @@ -138,7 +125,6 @@ protected void getPaths(Map<String, Object> restControllers) {

if (servletContextProvider.isPresent()) {
map = servletContextProvider.get().getMethods();
this.openAPIBuilder.addTag(new HashSet<>(map.values()), servletContextProvider.get().getTag());
calculatePath(restControllers, map, servletContextProvider);
}
if (this.springSecurityOAuth2Provider.isPresent()) {
Expand All @@ -151,7 +137,9 @@ protected void getPaths(Map<String, Object> restControllers) {
}
}

protected void calculatePath(Map<String, Object> restControllers, Map<RequestMappingInfo, HandlerMethod> map, Optional<ActuatorProvider> actuatorProvider) {
protected void calculatePath(Map<String, Object> restControllers,
Map<RequestMappingInfo, HandlerMethod> map,
Optional<ActuatorProvider> actuatorProvider) {
for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : map.entrySet()) {
RequestMappingInfo requestMappingInfo = entry.getKey();
HandlerMethod handlerMethod = entry.getValue();
Expand All @@ -161,36 +149,36 @@ protected void calculatePath(Map<String, Object> restControllers, Map<RequestMap
for (String pattern : patterns) {
String operationPath = PathUtils.parsePath(pattern, regexMap)
.replace("/{portal}/api", "");
if (((actuatorProvider.isPresent() && actuatorProvider.get().isRestController(operationPath))
if (((actuatorProvider.isPresent() && actuatorProvider.get().isRestController(operationPath, handlerMethod.getClass()))
|| isRestController(restControllers, handlerMethod, operationPath))
&& isPackageToScan(handlerMethod.getBeanType().getPackage())
&& isPathToMatch(operationPath)) {
Set<RequestMethod> requestMethods = requestMappingInfo.getMethodsCondition().getMethods();

// default allowed requestmethods
if (requestMethods.isEmpty())
requestMethods = this.getDefaultAllowedHttpMethods();
calculatePath(handlerMethod, operationPath, requestMethods);
// } else {
// System.out.println("API path ignored: " + operationPath);
}
}
}
// routerFunctionProvider.ifPresent(routerFunctions -> routerFunctions.getWebMvcRouterFunctionPaths()
// .ifPresent(routerBeans -> routerBeans.forEach(this::getRouterFunctionPaths)));
}

protected boolean isRestController(Map<String, Object> restControllers, HandlerMethod handlerMethod,
protected boolean isRestController(Map<String, Object> restControllers,
HandlerMethod handlerMethod,
String operationPath) {
ResponseBody responseBodyAnnotation = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), ResponseBody.class);
if (responseBodyAnnotation == null)
responseBodyAnnotation = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), ResponseBody.class);

return (responseBodyAnnotation != null && restControllers.containsKey(handlerMethod.getBean().toString()) || isAdditionalRestController(handlerMethod.getBeanType()))
return (restControllers.containsKey(handlerMethod.getBean().toString())
|| isAdditionalRestController(handlerMethod.getBeanType()))
&& operationPath.startsWith(DEFAULT_PATH_SEPARATOR)
&& (springDocConfigProperties.isModelAndViewAllowed() || !ModelAndView.class.isAssignableFrom(handlerMethod.getMethod().getReturnType()));
&& (springDocConfigProperties.isModelAndViewAllowed()
|| !ModelAndView.class.isAssignableFrom(handlerMethod.getMethod().getReturnType()));
}

protected void calculateServerUrl(HttpServletRequest request, String apiDocsUrl) {
String requestUrl = decode(request.getRequestURL().toString());
String calculatedUrl = requestUrl.substring(0, requestUrl.length() - apiDocsUrl.length());
openAPIBuilder.setServerBaseUrl(calculatedUrl);
this.openAPIService.setServerBaseUrl(calculatedUrl);
}
}
Expand Up @@ -28,20 +28,17 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jeeves.server.context.ServiceContext;
import org.fao.geonet.api.API;
import org.fao.geonet.api.ApiParams;
import org.fao.geonet.api.ApiUtils;
import org.fao.geonet.api.exception.ResourceNotFoundException;
import org.fao.geonet.domain.Language;
import org.fao.geonet.kernel.GeonetworkDataDirectory;
import org.fao.geonet.lib.DbLib;
import org.fao.geonet.lib.Lib;
import org.fao.geonet.repository.LanguageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
Expand All @@ -58,7 +55,7 @@
})
@Tag(name = "languages",
description = "Languages operations")
@Controller("languages")
@RestController
public class LanguagesApi {

@Autowired
Expand All @@ -67,6 +64,7 @@ public class LanguagesApi {
@Autowired
private GeonetworkDataDirectory dataDirectory;


@io.swagger.v3.oas.annotations.Operation(
summary = "Get languages",
description = "Languages for the application having translations in the database. " +
Expand Down
Expand Up @@ -39,7 +39,6 @@
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
Expand All @@ -48,7 +47,7 @@
/**
* Created by fgravin on 10/29/15.
*/
@Controller
@RestController
@RequestMapping(value = {
"/{portal}/api/workers/data/wfs/actions"
})
Expand Down Expand Up @@ -82,7 +81,6 @@ public JSONObject indexWfs(

@Operation(summary = "Delete a WFS feature type")
@RequestMapping(
// @RequestMapping(value = "/{serviceUrl:.*}/{typeName:.*}",
consumes = MediaType.ALL_VALUE,
produces = MediaType.ALL_VALUE,
method = RequestMethod.DELETE)
Expand Down

0 comments on commit 580a155

Please sign in to comment.