Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Java CI with Maven

on:
push:
pull_request:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn -B package --file pom.xml

Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package org.springdoc.core.configuration;

import java.util.function.Supplier;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static org.apache.commons.lang3.StringUtils.EMPTY;

public class SpringDocWebServerConfiguration {

/**
* WebServer context
*/
public interface SpringDocWebServerContext {
Supplier<Integer> getApplicationPort();

Supplier<Integer> getActuatorPort();

Supplier<ApplicationContext> getManagementApplicationContext();

String getContextPath();
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({WebServerInitializedEvent.class, ServerProperties.class})
static class EmbeddedWebServerConfiguration {

@Bean
SpringDocWebServerContext webServerPortProvider(ObjectProvider<ServerProperties> serverPropertiesProvider) {
return new SpringDocWebServerPortListener(serverPropertiesProvider);
}

static final class SpringDocWebServerPortListener
implements ApplicationListener<WebServerInitializedEvent>,
SpringDocWebServerContext {

private final String contextPath;

private volatile Supplier<Integer> applicationPortSupplier;
private volatile Supplier<Integer> actuatorPortSupplier;
private volatile Supplier<ApplicationContext> managementContextSupplier;

public SpringDocWebServerPortListener(ObjectProvider<ServerProperties> serverPropertiesProvider) {
ServerProperties serverProperties = serverPropertiesProvider.getIfAvailable();
contextPath = serverProperties != null
? StringUtils.defaultIfEmpty(serverProperties.getServlet().getContextPath(), EMPTY)
: EMPTY;
}

@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
final WebServer webServer = event.getWebServer();
if (WebServerApplicationContext.hasServerNamespace(event.getApplicationContext(), "management")) {
this.actuatorPortSupplier = webServer::getPort;
this.managementContextSupplier = event::getApplicationContext;
}
else {
this.applicationPortSupplier = webServer::getPort;
}
}

@Override
public Supplier<Integer> getApplicationPort() {
return applicationPortSupplier;
}

@Override
public Supplier<Integer> getActuatorPort() {
return actuatorPortSupplier;
}

@Override
public Supplier<ApplicationContext> getManagementApplicationContext() {
return this.managementContextSupplier;
}

@Override
public String getContextPath() {
return contextPath;
}

}
}

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass({"org.springframework.boot.web.server.context.WebServerInitializedEvent", "org.springframework.boot.web.server.autoconfigure.ServerProperties"})
static class DeployedWebServerConfiguration {

@Bean
@ConditionalOnMissingBean(SpringDocWebServerContext.class)
SpringDocWebServerContext webServerPortProvider() {
return new SpringDocWebServerContext() {
@Override
public Supplier<Integer> getApplicationPort() {
return () -> -1;
}

@Override
public Supplier<Integer> getActuatorPort() {
return () -> -1;
}

@Override
public Supplier<ApplicationContext> getManagementApplicationContext() {
return () -> null;
}

@Override
public String getContextPath() {
return EMPTY;
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,15 @@
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.tags.Tag;
import org.springdoc.api.AbstractOpenApiResource;
import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.utils.Constants;

import org.springframework.beans.BeansException;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.method.HandlerMethod;

Expand All @@ -56,7 +52,7 @@
*
* @author bnasslahsen
*/
public abstract class ActuatorProvider implements ApplicationListener<WebServerInitializedEvent>, ApplicationContextAware {
public abstract class ActuatorProvider implements ApplicationContextAware {

/**
* The Management server properties.
Expand All @@ -68,31 +64,17 @@ public abstract class ActuatorProvider implements ApplicationListener<WebServerI
*/
protected WebEndpointProperties webEndpointProperties;


/**
* The Server properties.
*/
protected ServerProperties serverProperties;
* The server context
*/
protected SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext;

/**
* The Spring doc config properties.
*/
protected SpringDocConfigProperties springDocConfigProperties;

/**
* The Actuator web server.
*/
protected WebServer actuatorWebServer;

/**
* The Application web server.
*/
protected WebServer applicationWebServer;

/**
* The Management application context.
*/
protected ApplicationContext managementApplicationContext;

/**
* The Application context.
*/
Expand All @@ -103,19 +85,19 @@ public abstract class ActuatorProvider implements ApplicationListener<WebServerI
*
* @param managementServerProperties the management server properties
* @param webEndpointProperties the web endpoint properties
* @param serverProperties the server properties
* @param springDocWebServerContext the server context
* @param springDocConfigProperties the spring doc config properties
*/
protected ActuatorProvider(Optional<ManagementServerProperties> managementServerProperties,
Optional<WebEndpointProperties> webEndpointProperties,
ServerProperties serverProperties,
SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
SpringDocConfigProperties springDocConfigProperties) {

managementServerProperties.ifPresent(managementServerProperties1 -> this.managementServerProperties = managementServerProperties1);
webEndpointProperties.ifPresent(webEndpointProperties1 -> this.webEndpointProperties = webEndpointProperties1);

this.serverProperties = serverProperties;
this.springDocConfigProperties = springDocConfigProperties;
this.springDocWebServerContext = springDocWebServerContext;
}

/**
Expand All @@ -135,16 +117,6 @@ public static Tag getTag() {
return actuatorTag;
}

@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
if (WebServerApplicationContext.hasServerNamespace(event.getApplicationContext(), "management")) {
managementApplicationContext = event.getApplicationContext();
actuatorWebServer = event.getWebServer();
}
else {
applicationWebServer = event.getWebServer();
}
}

/**
* Is rest controller boolean.
Expand Down Expand Up @@ -201,7 +173,7 @@ public String getActuatorPath() {
* @return the application port
*/
public int getApplicationPort() {
return applicationWebServer.getPort();
return this.springDocWebServerContext.getApplicationPort().get();
}

/**
Expand All @@ -210,7 +182,7 @@ public int getApplicationPort() {
* @return the actuator port
*/
public int getActuatorPort() {
return actuatorWebServer.getPort();
return this.springDocWebServerContext.getActuatorPort().get();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ org.springdoc.core.configuration.SpringDocSpecPropertiesConfiguration
org.springdoc.core.configuration.SpringDocDataRestConfiguration
org.springdoc.core.configuration.SpringDocKotlinConfiguration
org.springdoc.core.configuration.SpringDocKotlinxConfiguration
org.springdoc.core.configuration.SpringDocJacksonKotlinModuleConfiguration
org.springdoc.core.configuration.SpringDocJacksonKotlinModuleConfiguration
org.springdoc.core.configuration.SpringDocWebServerConfiguration.EmbeddedWebServerConfiguration
org.springdoc.core.configuration.SpringDocWebServerConfiguration.DeployedWebServerConfiguration
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.Optional;

import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
import org.springdoc.core.customizers.SpringDocCustomizers;
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
import org.springdoc.core.extractor.MethodParameterPojoExtractor;
Expand Down Expand Up @@ -60,7 +61,6 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -165,7 +165,7 @@ static class SpringDocWebFluxActuatorConfiguration {
/**
* Actuator provider actuator provider.
*
* @param serverProperties the server properties
* @param springDocWebServerContext the server context
* @param springDocConfigProperties the spring doc config properties
* @param managementServerProperties the management server properties
* @param webEndpointProperties the web endpoint properties
Expand All @@ -175,11 +175,11 @@ static class SpringDocWebFluxActuatorConfiguration {
@ConditionalOnMissingBean
@ConditionalOnExpression("${springdoc.show-actuator:false} or ${springdoc.use-management-port:false}")
@Lazy(false)
ActuatorProvider actuatorProvider(ServerProperties serverProperties,
ActuatorProvider actuatorProvider(SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
SpringDocConfigProperties springDocConfigProperties,
Optional<ManagementServerProperties> managementServerProperties,
Optional<WebEndpointProperties> webEndpointProperties) {
return new ActuatorWebFluxProvider(serverProperties,
return new ActuatorWebFluxProvider(springDocWebServerContext,
springDocConfigProperties,
managementServerProperties,
webEndpointProperties);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@
import java.util.Map;
import java.util.Optional;

import org.springdoc.core.configuration.SpringDocWebServerConfiguration;
import org.springdoc.core.properties.SpringDocConfigProperties;
import org.springdoc.core.providers.ActuatorProvider;

import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
import org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.context.ApplicationContextAware;
Expand All @@ -54,29 +54,29 @@ public class ActuatorWebFluxProvider extends ActuatorProvider implements Applica
/**
* Instantiates a new Actuator web flux provider.
*
* @param serverProperties the server properties
* @param springDocWebServerContext the server context
* @param springDocConfigProperties the spring doc config properties
* @param managementServerProperties the management server properties
* @param webEndpointProperties the web endpoint properties
*/
public ActuatorWebFluxProvider(ServerProperties serverProperties,
public ActuatorWebFluxProvider(SpringDocWebServerConfiguration.SpringDocWebServerContext springDocWebServerContext,
SpringDocConfigProperties springDocConfigProperties,
Optional<ManagementServerProperties> managementServerProperties,
Optional<WebEndpointProperties> webEndpointProperties) {
super(managementServerProperties, webEndpointProperties, serverProperties, springDocConfigProperties);
super(managementServerProperties, webEndpointProperties, springDocWebServerContext, springDocConfigProperties);
}

public Map<RequestMappingInfo, HandlerMethod> getMethods() {
Map<RequestMappingInfo, HandlerMethod> mappingInfoHandlerMethodMap = new HashMap<>();

WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping = applicationContext.getBeansOfType(WebFluxEndpointHandlerMapping.class).values().stream().findFirst().orElse(null);
if (webFluxEndpointHandlerMapping == null)
webFluxEndpointHandlerMapping = managementApplicationContext.getBean(WebFluxEndpointHandlerMapping.class);
webFluxEndpointHandlerMapping = springDocWebServerContext.getManagementApplicationContext().get().getBean(WebFluxEndpointHandlerMapping.class);
mappingInfoHandlerMethodMap.putAll(webFluxEndpointHandlerMapping.getHandlerMethods());

ControllerEndpointHandlerMapping controllerEndpointHandlerMapping = applicationContext.getBeansOfType(ControllerEndpointHandlerMapping.class).values().stream().findFirst().orElse(null);
if (controllerEndpointHandlerMapping == null)
controllerEndpointHandlerMapping = managementApplicationContext.getBean(ControllerEndpointHandlerMapping.class);
controllerEndpointHandlerMapping = springDocWebServerContext.getManagementApplicationContext().get().getBean(ControllerEndpointHandlerMapping.class);
mappingInfoHandlerMethodMap.putAll(controllerEndpointHandlerMapping.getHandlerMethods());

return mappingInfoHandlerMethodMap;
Expand Down
Loading