diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java index 85296fc8b..183a8c0b2 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfiguration.java @@ -49,11 +49,13 @@ import org.springdoc.core.customizers.ActuatorOperationCustomizer; import org.springdoc.core.customizers.DataRestDelegatingMethodParameterCustomizer; import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer; +import org.springdoc.core.customizers.GlobalOpenApiCustomiser; +import org.springdoc.core.customizers.GlobalOperationCustomizer; import org.springdoc.core.customizers.OpenApiBuilderCustomizer; import org.springdoc.core.customizers.OpenApiCustomiser; -import org.springdoc.core.customizers.OperationCustomizer; import org.springdoc.core.customizers.PropertyCustomizer; import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.filters.GlobalOpenApiMethodFilter; import org.springdoc.core.providers.ActuatorProvider; import org.springdoc.core.providers.CloudFunctionProvider; import org.springdoc.core.providers.JavadocProvider; @@ -85,6 +87,7 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Scope; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.convert.support.GenericConversionService; import org.springframework.data.domain.Pageable; @@ -109,6 +112,7 @@ /** * The type Spring doc configuration. * @author bnasslahsen + * @author christophejan */ @Lazy(false) @Configuration(proxyBeanMethods = false) @@ -359,7 +363,7 @@ OpenApiCustomiser propertiesResolverForSchema(PropertyResolverUtils propertyReso @Conditional(CacheOrGroupedOpenApiCondition.class) @ConditionalOnClass(name = BINDRESULT_CLASS) @Lazy(false) - static BeanFactoryPostProcessor springdocBeanFactoryPostProcessor() { + static SpringdocBeanFactoryConfigurer springdocBeanFactoryPostProcessor() { return new SpringdocBeanFactoryConfigurer(); } @@ -397,6 +401,18 @@ SpringDocProviders springDocProviders(Optional actuatorProvide return new SpringDocProviders(actuatorProvider, springCloudFunctionProvider, springSecurityOAuth2Provider, repositoryRestResourceProvider, routerFunctionProvider, springWebProvider); } + @Bean + @Scope("prototype") + @ConditionalOnMissingBean + public GroupedOpenApi.Builder groupedOpenApiBuilder(List globalOpenApiCustomisers, List globalOperationCustomizers, + List globalOpenApiMethodFilters) { + GroupedOpenApi.Builder builder = GroupedOpenApi.builder(); + globalOpenApiCustomisers.forEach(builder::addOpenApiCustomiser); + globalOperationCustomizers.forEach(builder::addOperationCustomizer); + globalOpenApiMethodFilters.forEach(builder::addOpenApiMethodFilter); + return builder; + } + /** * The type Open api resource advice. * @author bnasslashen @@ -428,15 +444,14 @@ static class SpringDocActuatorConfiguration { /** * Springdoc bean factory post processor 3 bean factory post processor. * - * @param groupedOpenApis the grouped open apis * @return the bean factory post processor */ @Bean @Lazy(false) @ConditionalOnManagementPort(ManagementPortType.DIFFERENT) @Conditional(MultipleOpenApiSupportCondition.class) - static BeanFactoryPostProcessor springdocBeanFactoryPostProcessor3(List groupedOpenApis) { - return new SpringdocActuatorBeanFactoryConfigurer(groupedOpenApis); + static SpringdocActuatorBeanFactoryConfigurer springdocBeanFactoryPostProcessor3() { + return new SpringdocActuatorBeanFactoryConfigurer(); } /** @@ -447,7 +462,7 @@ static BeanFactoryPostProcessor springdocBeanFactoryPostProcessor3(List groupedOpenApis; + protected ApplicationContext applicationContext; - /** - * Instantiates a new Springdoc actuator bean factory configurer. - * - * @param groupedOpenApis the grouped open apis - */ - public SpringdocActuatorBeanFactoryConfigurer(List groupedOpenApis) { - this.groupedOpenApis = groupedOpenApis; + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; } @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - final BindResult result = Binder.get(environment) + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { + final BindResult result = Binder.get(applicationContext.getEnvironment()) .bind(MANAGEMENT_ENDPOINTS_WEB, WebEndpointProperties.class); if (result.isBound()) { WebEndpointProperties webEndpointProperties = result.get(); - List newGroups = new ArrayList<>(); - - ActuatorOpenApiCustomizer actuatorOpenApiCustomiser = new ActuatorOpenApiCustomizer(webEndpointProperties); - beanFactory.registerSingleton("actuatorOpenApiCustomiser", actuatorOpenApiCustomiser); - ActuatorOperationCustomizer actuatorCustomizer = new ActuatorOperationCustomizer(); - beanFactory.registerSingleton("actuatorCustomizer", actuatorCustomizer); - - GroupedOpenApi actuatorGroup = GroupedOpenApi.builder().group(ACTUATOR_DEFAULT_GROUP) - .pathsToMatch(webEndpointProperties.getBasePath() + ALL_PATTERN) - .pathsToExclude(webEndpointProperties.getBasePath() + HEALTH_PATTERN) - .addOperationCustomizer(actuatorCustomizer) - .addOpenApiCustomiser(actuatorOpenApiCustomiser) - .build(); - // Add the actuator group - newGroups.add(actuatorGroup); - - if (CollectionUtils.isEmpty(groupedOpenApis)) { - GroupedOpenApi defaultGroup = GroupedOpenApi.builder().group(DEFAULT_GROUP_NAME) - .pathsToMatch(ALL_PATTERN) - .pathsToExclude(webEndpointProperties.getBasePath() + ALL_PATTERN) - .build(); - // Register the default group - newGroups.add(defaultGroup); - } + boolean addDefaultGroup = ObjectUtils.isEmpty(applicationContext + .getBeanNamesForType(GroupedOpenApi.class, true, false)); + + registry.registerBeanDefinition("actuatorOpenApiCustomiser", BeanDefinitionBuilder + .genericBeanDefinition(ActuatorOpenApiCustomizer.class) + .addConstructorArgValue(webEndpointProperties) + .getBeanDefinition()); + + registry.registerBeanDefinition("actuatorCustomizer", BeanDefinitionBuilder + .genericBeanDefinition(ActuatorOperationCustomizer.class) + .getBeanDefinition()); - newGroups.forEach(elt -> beanFactory.registerSingleton(elt.getGroup(), elt)); + // register the actuator group bean definition + registry.registerBeanDefinition(ACTUATOR_DEFAULT_GROUP, BeanDefinitionBuilder + .genericBeanDefinition(SpringdocActuatorBeanFactoryConfigurer.class) + .setFactoryMethod("actuatorGroupFactoryMethod") + .addConstructorArgValue(new RuntimeBeanReference(GroupedOpenApi.Builder.class)) + .addConstructorArgValue(webEndpointProperties.getBasePath()) + .addConstructorArgValue(new RuntimeBeanReference(ActuatorOpenApiCustomizer.class)) + .addConstructorArgValue(new RuntimeBeanReference(ActuatorOperationCustomizer.class)) + .getBeanDefinition()); + + if (addDefaultGroup) { + // register the default group bean definition + registry.registerBeanDefinition(DEFAULT_GROUP_NAME, BeanDefinitionBuilder + .genericBeanDefinition(SpringdocActuatorBeanFactoryConfigurer.class) + .setFactoryMethod("defaultGroupFactoryMethod") + .addConstructorArgValue(new RuntimeBeanReference(GroupedOpenApi.Builder.class)) + .addConstructorArgValue(webEndpointProperties.getBasePath()) + .getBeanDefinition()); + } } - initBeanFactoryPostProcessor(beanFactory); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + SpringdocBeanFactoryConfigurer.initBeanFactoryPostProcessor(beanFactory); + } + + /** + * Actuator {@link GroupedOpenApi} factory method. + * + * @param builder the {@link GroupedOpenApi.Builder} + * @param actuatorBasePath the actuator base path + * @param actuatorOpenApiCustomiser the {@link ActuatorOpenApiCustomizer} + * @param actuatorOperationCustomizer the {@link ActuatorOperationCustomizer} + * + * @return the actuator {@link GroupedOpenApi} + */ + public static GroupedOpenApi actuatorGroupFactoryMethod(GroupedOpenApi.Builder builder, String actuatorBasePath, + ActuatorOpenApiCustomizer actuatorOpenApiCustomiser, ActuatorOperationCustomizer actuatorOperationCustomizer) { + return builder.group(ACTUATOR_DEFAULT_GROUP) + .pathsToMatch(actuatorBasePath + ALL_PATTERN) + .pathsToExclude(actuatorBasePath + HEALTH_PATTERN) + .addOpenApiCustomiser(actuatorOpenApiCustomiser) + .addOperationCustomizer(actuatorOperationCustomizer) + .build(); + } + + /** + * Default {@link GroupedOpenApi} factory method. + * + * @param builder the {@link GroupedOpenApi.Builder} + * @param actuatorBasePath the actuator base path + * + * @return the default {@link GroupedOpenApi} + */ + public static GroupedOpenApi defaultGroupFactoryMethod(GroupedOpenApi.Builder builder, String actuatorBasePath) { + return builder.group(DEFAULT_GROUP_NAME) + .pathsToMatch(ALL_PATTERN) + .pathsToExclude(actuatorBasePath + ALL_PATTERN) + .build(); } } diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringdocBeanFactoryConfigurer.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringdocBeanFactoryConfigurer.java index 353978ccb..1cd481644 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringdocBeanFactoryConfigurer.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/SpringdocBeanFactoryConfigurer.java @@ -2,7 +2,7 @@ * * * * * * - * * * * Copyright 2019-2020 the original author or authors. + * * * * 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. @@ -23,18 +23,19 @@ package org.springdoc.core; -import java.util.List; -import java.util.stream.Collectors; - import io.swagger.v3.oas.models.OpenAPI; -import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springdoc.core.SpringDocConfigProperties.GroupConfig; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.boot.context.properties.bind.BindResult; import org.springframework.boot.context.properties.bind.Binder; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.env.Environment; -import org.springframework.lang.Nullable; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.util.CollectionUtils; import static org.springdoc.core.Constants.SPRINGDOC_PREFIX; @@ -43,41 +44,58 @@ /** * The type Springdoc bean factory configurer. * @author bnasslahsen + * @author christophejan */ -public class SpringdocBeanFactoryConfigurer implements EnvironmentAware, BeanFactoryPostProcessor { +public class SpringdocBeanFactoryConfigurer implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor { /** - * The Environment. + * The ApplicationContext. */ - @Nullable - protected Environment environment; + protected ApplicationContext applicationContext; @Override - public void setEnvironment(Environment environment) { - this.environment = environment; + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + this.applicationContext = applicationContext; } @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - final BindResult result = Binder.get(environment) + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { + final BindResult result = Binder.get(applicationContext.getEnvironment()) .bind(SPRINGDOC_PREFIX, SpringDocConfigProperties.class); if (result.isBound()) { - SpringDocConfigProperties springDocGroupConfig = result.get(); - List groupedOpenApis = springDocGroupConfig.getGroupConfigs().stream() - .map(elt -> { - GroupedOpenApi.Builder builder = GroupedOpenApi.builder(); - if (!CollectionUtils.isEmpty(elt.getPackagesToScan())) - builder.packagesToScan(elt.getPackagesToScan().toArray(new String[0])); - if (!CollectionUtils.isEmpty(elt.getPathsToMatch())) - builder.pathsToMatch(elt.getPathsToMatch().toArray(new String[0])); - return builder.group(elt.getGroup()).build(); - }) - .collect(Collectors.toList()); - groupedOpenApis.forEach(elt -> beanFactory.registerSingleton(elt.getGroup(), elt)); + result.get().getGroupConfigs().stream().forEach(groupConfig -> + // register bean definitions + registry.registerBeanDefinition(groupConfig.getGroup(), BeanDefinitionBuilder + .genericBeanDefinition(SpringdocBeanFactoryConfigurer.class) + .setFactoryMethod("groupedOpenApisFactoryMethod") + .addConstructorArgValue(new RuntimeBeanReference(GroupedOpenApi.Builder.class)) + .addConstructorArgValue(groupConfig) + .getBeanDefinition()) + ); } + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { initBeanFactoryPostProcessor(beanFactory); } + /** + * {@link GroupedOpenApi} factory method from {@link GroupConfig}. + * + * @param builder the {@link GroupedOpenApi.Builder} + * @param groupConfig the {@link GroupConfig} + * + * @return the {@link GroupedOpenApi} + */ + public static GroupedOpenApi groupedOpenApisFactoryMethod(GroupedOpenApi.Builder builder, GroupConfig groupConfig) { + if (!CollectionUtils.isEmpty(groupConfig.getPackagesToScan())) + builder.packagesToScan(groupConfig.getPackagesToScan().toArray(new String[0])); + if (!CollectionUtils.isEmpty(groupConfig.getPathsToMatch())) + builder.pathsToMatch(groupConfig.getPathsToMatch().toArray(new String[0])); + return builder.group(groupConfig.getGroup()).build(); + } + /** * Init bean factory post processor. * diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOpenApiCustomiser.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOpenApiCustomiser.java new file mode 100644 index 000000000..dc6d1cf11 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOpenApiCustomiser.java @@ -0,0 +1,32 @@ +/* + * + * * + * * * 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.core.customizers; + +/** + * Implement and register a bean of type {@link GlobalOpenApiCustomiser} to + * customize Open api on default OpenAPI description and groups. + * + * @author christophejan + * @see OpenApiCustomiser to customize default OpenAPI description but not + * groups + */ +public interface GlobalOpenApiCustomiser extends OpenApiCustomiser { +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOperationCustomizer.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOperationCustomizer.java new file mode 100644 index 000000000..544087ac7 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/GlobalOperationCustomizer.java @@ -0,0 +1,33 @@ +/* + * + * * + * * * 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.core.customizers; + +/** + * Implement and register a bean of type {@link GlobalOperationCustomizer} to + * customize an operation based on the handler method input on default OpenAPI + * description and groups + * + * @author christophejan + * @see OperationCustomizer to customize operations on default OpenAPI + * description but not groups + */ +public interface GlobalOperationCustomizer extends OperationCustomizer { +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OpenApiCustomiser.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OpenApiCustomiser.java index c3573645b..d9146c0f8 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OpenApiCustomiser.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OpenApiCustomiser.java @@ -1,7 +1,7 @@ /* * * * - * * * Copyright 2019-2020 the original author or authors. + * * * 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. @@ -23,8 +23,12 @@ import io.swagger.v3.oas.models.OpenAPI; /** - * The interface Open api customiser. + * Implement and register a bean of type {@link OpenApiCustomiser} to customize + * Open api on default OpenAPI description but not on groups + * * @author bnasslahsen + * @see GlobalOpenApiCustomiser to customize default OpenAPI description and + * groups */ @FunctionalInterface public interface OpenApiCustomiser { diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OperationCustomizer.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OperationCustomizer.java index 4e7caf9da..b55a9813e 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OperationCustomizer.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/OperationCustomizer.java @@ -1,7 +1,7 @@ /* * * * - * * * Copyright 2019-2020 the original author or authors. + * * * 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. @@ -26,8 +26,12 @@ /** * Implement and register a bean of type {@link OperationCustomizer} to customize an operation - * based on the handler method input + * based on the handler method input on default OpenAPI descriptions but not + * groups + * * @author bnasslahsen + * @see GlobalOperationCustomizer to customize operations on default OpenAPI + * description and groups */ @FunctionalInterface public interface OperationCustomizer { diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/GlobalOpenApiMethodFilter.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/GlobalOpenApiMethodFilter.java new file mode 100644 index 000000000..56fd74d18 --- /dev/null +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/GlobalOpenApiMethodFilter.java @@ -0,0 +1,34 @@ +/* + * + * * + * * * 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.core.filters; + +/** + * Implement and register a bean of type {@link GlobalOpenApiMethodFilter} to + * conditionally including any detected methods in default OpenAPI description + * and groups. + * + * @author michael.clarke + * @see OpenApiMethodFilter to filter methods in default OpenAPI description but + * not groups + */ +@FunctionalInterface +public interface GlobalOpenApiMethodFilter extends OpenApiMethodFilter { +} diff --git a/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/OpenApiMethodFilter.java b/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/OpenApiMethodFilter.java index 317967d6b..ede876093 100644 --- a/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/OpenApiMethodFilter.java +++ b/springdoc-openapi-common/src/main/java/org/springdoc/core/filters/OpenApiMethodFilter.java @@ -1,7 +1,7 @@ /* * * * - * * * Copyright 2019-2020 the original author or authors. + * * * 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. @@ -23,8 +23,13 @@ import java.lang.reflect.Method; /** - * A filter to allow conditionally including any detected methods in an OpenApi definition. + * Implement and register a bean of type {@link OpenApiMethodFilter} to + * conditionally include any detected methods in default OpenAPI descriptions + * but not groups + * * @author michael.clarke + * @see GlobalOpenApiMethodFilter to filter methods in default OpenAPI + * description and groups */ @FunctionalInterface public interface OpenApiMethodFilter { diff --git a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java index 562aea29e..e902c09cd 100644 --- a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java +++ b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java @@ -1,6 +1,6 @@ /* * - * * Copyright 2019-2020 the original author or authors. + * * 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. @@ -18,6 +18,9 @@ package test.org.springdoc.api.app145; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import org.junit.jupiter.api.Test; import org.springdoc.core.Constants; import test.org.springdoc.api.AbstractSpringDocActuatorTest; @@ -25,6 +28,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.WebClientResponseException; @SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT, @@ -47,4 +52,19 @@ public void testApp() { .expectStatus().isNotFound(); } + @Test + public void testApp3() throws Exception { + try { + webClient.get().uri("/application/openapi"+ "/"+Constants.DEFAULT_GROUP_NAME).retrieve() + .bodyToMono(String.class).block(); + fail(); + } + catch (WebClientResponseException ex) { + if (ex.getStatusCode() == HttpStatus.NOT_FOUND) + assertTrue(true); + else + fail(); + } + } + } diff --git a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java index c2119a616..238402a31 100644 --- a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java +++ b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java @@ -68,4 +68,11 @@ public void testApp1() throws Exception { assertEquals(expected, result, true); } + @Test + public void testApp2() throws Exception { + webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/"+Constants.DEFAULT_GROUP_NAME) + .exchange() + .expectStatus().isNotFound(); + } + } diff --git a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java index e1df88b08..83e14f980 100644 --- a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java +++ b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java @@ -19,12 +19,18 @@ package test.org.springdoc.api.app148; import org.junit.jupiter.api.Test; +import org.springdoc.core.Constants; + import test.org.springdoc.api.AbstractSpringDocActuatorTest; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.WebClientResponseException; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @@ -59,4 +65,18 @@ public void testApp2() throws Exception { assertEquals(expected, result, true); } + @Test + public void testApp3() throws Exception { + try { + webClient.get().uri("/test/application/openapi" + "/"+Constants.DEFAULT_GROUP_NAME).retrieve() + .bodyToMono(String.class).block(); + fail(); + } + catch (WebClientResponseException ex) { + if (ex.getStatusCode() == HttpStatus.NOT_FOUND) + assertTrue(true); + else + fail(); + } + } } diff --git a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/HelloController.java b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/HelloController.java new file mode 100644 index 000000000..a38bd2590 --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/HelloController.java @@ -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 test.org.springdoc.api.app184; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + @GetMapping("/globalBeanFiltered") + public String globalBeanFiltered() { + return "globalBeanFiltered"; + } + + @GetMapping("/beanFiltered") + public String beanFiltered() { + return "beanFiltered"; + } + + @GetMapping("/group1Filtered") + public String group1Filtered() { + return "group1Filtered"; + } + + @GetMapping("/group2Filtered") + public String group2Filtered() { + return "group2Filtered"; + } + + @GetMapping("/group3Filtered") + public String group3Filtered() { + return "group3Filtered"; + } + +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java new file mode 100644 index 000000000..c9ece5f1b --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java @@ -0,0 +1,126 @@ +/* + * + * * + * * * 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 + * * * + * * * 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 test.org.springdoc.api.app184; + +import java.util.Objects; + +import org.junit.jupiter.api.Test; +import org.springdoc.core.Constants; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.customizers.GlobalOpenApiCustomiser; +import org.springdoc.core.customizers.GlobalOperationCustomizer; +import org.springdoc.core.customizers.OpenApiCustomiser; +import org.springdoc.core.customizers.OperationCustomizer; +import org.springdoc.core.filters.GlobalOpenApiMethodFilter; +import org.springdoc.core.filters.OpenApiMethodFilter; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.test.context.TestPropertySource; + +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.servers.Server; +import test.org.springdoc.api.AbstractSpringDocTest; + +@TestPropertySource(properties = { + "springdoc.group-configs[0].group=group1", + "springdoc.group-configs[0].paths-to-exclude=/group1Filtered", +}) +public class SpringDocAppapp184Test extends AbstractSpringDocTest { + + @SpringBootApplication + @ComponentScan(basePackages = { "org.springdoc", "test.org.springdoc.api.app184" }) + static class SpringDocTestApp { + + @Bean + public GlobalOpenApiCustomiser addUrlGlobalBean() { + return openApi -> openApi.getServers().add(new Server().url("urlGlobalBean")); + } + + @Bean + public OpenApiCustomiser addUrlBean() { + return openApi -> openApi.getServers().add(new Server().url("urlBean")); + } + + @Bean + public GlobalOperationCustomizer addHeaderGlobaBeanl() { + return (operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGlobalBean")); + } + + @Bean + public OperationCustomizer addHeaderBean() { + return (operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerBean")); + } + + @Bean + public GlobalOpenApiMethodFilter globalFilterBean() { + return method -> !Objects.equals(method.getName(), "globalBeanFiltered"); + } + + @Bean + public OpenApiMethodFilter filterBean() { + return method -> !Objects.equals(method.getName(), "beanFiltered"); + } + + @Bean + public GroupedOpenApi group2(GroupedOpenApi.Builder builder) { + return builder + .group("group2") + .addOpenApiCustomiser(openApi -> openApi.getServers().add(new Server().url("urlGroup2"))) + .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGroup2"))) + .addOpenApiMethodFilter(method -> !Objects.equals(method.getName(), "group2Filtered")) + .build(); + } + + @Bean + public GroupedOpenApi group3(GroupedOpenApi.Builder builder) { + return builder + .group("group3") + .addOpenApiCustomiser(openApi -> openApi.getServers().add(new Server().url("urlGroup3"))) + .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGroup3"))) + .addOpenApiMethodFilter(method -> !Objects.equals(method.getName(), "group3Filtered")) + .build(); + } + + } + + @Test + public void testGroup1() throws Exception { + webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group1").exchange() + .expectStatus().isOk() + .expectBody().json(getContent("results/app184-1.json"), true); + } + + @Test + public void testGroup2() throws Exception { + webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group2").exchange() + .expectStatus().isOk() + .expectBody().json(getContent("results/app184-2.json"), true); + } + + @Test + public void testGroup3() throws Exception { + webTestClient.get().uri(Constants.DEFAULT_API_DOCS_URL + "/group3").exchange() + .expectStatus().isOk() + .expectBody().json(getContent("results/app184-3.json"), true); + } + +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-core/src/test/resources/results/app184-1.json b/springdoc-openapi-webflux-core/src/test/resources/results/app184-1.json new file mode 100644 index 000000000..45c4c8fe7 --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/resources/results/app184-1.json @@ -0,0 +1,97 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-core/src/test/resources/results/app184-2.json b/springdoc-openapi-webflux-core/src/test/resources/results/app184-2.json new file mode 100644 index 000000000..84456de29 --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/resources/results/app184-2.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlGroup2" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-core/src/test/resources/results/app184-3.json b/springdoc-openapi-webflux-core/src/test/resources/results/app184-3.json new file mode 100644 index 000000000..3fd154b16 --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/resources/results/app184-3.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlGroup3" + } + ], + "paths": { + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webflux-core/src/test/resources/results/app184.json b/springdoc-openapi-webflux-core/src/test/resources/results/app184.json new file mode 100644 index 000000000..bfa5b82d0 --- /dev/null +++ b/springdoc-openapi-webflux-core/src/test/resources/results/app184.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlBean" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java index f103e27d7..837edc153 100644 --- a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app145/SpringDocApp145Test.java @@ -1,6 +1,6 @@ /* * - * * Copyright 2019-2020 the original author or authors. + * * 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. @@ -27,6 +27,7 @@ import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.http.HttpStatus; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpStatusCodeException; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -75,4 +76,18 @@ public void testApp2() throws Exception { assertEquals(expected, result, true); } + @Test + public void testApp3() throws Exception { + try { + actuatorRestTemplate.getForObject("/application/openapi"+ "/"+Constants.DEFAULT_GROUP_NAME, String.class); + fail(); + } + catch (HttpStatusCodeException ex) { + // TODO: Currently obtain status 500 on MVC... Webflux obtain 404... + if (ex.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) + assertTrue(true); + else + fail(); + } + } } diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java index 5cebf46f6..9a574cb27 100644 --- a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app147/SpringDocApp147Test.java @@ -1,6 +1,6 @@ /* * - * * Copyright 2019-2020 the original author or authors. + * * 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. @@ -61,4 +61,10 @@ public void testApp1() throws Exception { .andExpect(content().json(getContent("results/app147-2.json"), true)); } + @Test + public void testApp2() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL + "/"+Constants.DEFAULT_GROUP_NAME)) + .andExpect(status().isNotFound()); + } + } diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java index 50f51e4de..1a717a460 100644 --- a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java @@ -1,6 +1,6 @@ /* * - * * Copyright 2019-2020 the original author or authors. + * * 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. @@ -19,12 +19,18 @@ package test.org.springdoc.api.app148; import org.junit.jupiter.api.Test; +import org.springdoc.core.Constants; + import test.org.springdoc.api.AbstractSpringDocActuatorTest; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpStatusCodeException; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; @@ -59,4 +65,19 @@ public void testApp2() throws Exception { assertEquals(expected, result, true); } + @Test + public void testApp3() throws Exception { + try { + actuatorRestTemplate.getForObject("/test/application/openapi" + "/"+Constants.DEFAULT_GROUP_NAME, String.class); + fail(); + } + catch (HttpStatusCodeException ex) { + // TODO: Currently obtain status 500 on MVC... Webflux obtain 404... + if (ex.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) + assertTrue(true); + else + fail(); + } + } + } diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/HelloController.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/HelloController.java new file mode 100644 index 000000000..a38bd2590 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/HelloController.java @@ -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 test.org.springdoc.api.app184; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HelloController { + + @GetMapping("/globalBeanFiltered") + public String globalBeanFiltered() { + return "globalBeanFiltered"; + } + + @GetMapping("/beanFiltered") + public String beanFiltered() { + return "beanFiltered"; + } + + @GetMapping("/group1Filtered") + public String group1Filtered() { + return "group1Filtered"; + } + + @GetMapping("/group2Filtered") + public String group2Filtered() { + return "group2Filtered"; + } + + @GetMapping("/group3Filtered") + public String group3Filtered() { + return "group3Filtered"; + } + +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java new file mode 100644 index 000000000..085145626 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/java/test/org/springdoc/api/app184/SpringDocAppapp184Test.java @@ -0,0 +1,126 @@ +/* + * + * * 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 + * * + * * 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 test.org.springdoc.api.app184; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.util.Objects; + +import org.junit.jupiter.api.Test; +import org.springdoc.core.Constants; +import org.springdoc.core.GroupedOpenApi; +import org.springdoc.core.customizers.GlobalOpenApiCustomiser; +import org.springdoc.core.customizers.GlobalOperationCustomizer; +import org.springdoc.core.customizers.OpenApiCustomiser; +import org.springdoc.core.customizers.OperationCustomizer; +import org.springdoc.core.filters.GlobalOpenApiMethodFilter; +import org.springdoc.core.filters.OpenApiMethodFilter; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.TestPropertySource; + +import io.swagger.v3.oas.models.parameters.HeaderParameter; +import io.swagger.v3.oas.models.servers.Server; +import test.org.springdoc.api.AbstractSpringDocTest; + +@TestPropertySource(properties = { + "springdoc.group-configs[0].group=group1", + "springdoc.group-configs[0].paths-to-exclude=/group1Filtered", +}) +public class SpringDocAppapp184Test extends AbstractSpringDocTest { + + @SpringBootApplication + static class SpringDocTestApp { + + @Bean + public GlobalOpenApiCustomiser addUrlGlobalBean() { + return openApi -> openApi.getServers().add(new Server().url("urlGlobalBean")); + } + + @Bean + public OpenApiCustomiser addUrlBean() { + return openApi -> openApi.getServers().add(new Server().url("urlBean")); + } + + @Bean + public GlobalOperationCustomizer addHeaderGlobaBeanl() { + return (operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGlobalBean")); + } + + @Bean + public OperationCustomizer addHeaderBean() { + return (operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerBean")); + } + + @Bean + public GlobalOpenApiMethodFilter globalFilterBean() { + return method -> !Objects.equals(method.getName(), "globalBeanFiltered"); + } + + @Bean + public OpenApiMethodFilter filterBean() { + return method -> !Objects.equals(method.getName(), "beanFiltered"); + } + + @Bean + public GroupedOpenApi group2(GroupedOpenApi.Builder builder) { + return builder + .group("group2") + .addOpenApiCustomiser(openApi -> openApi.getServers().add(new Server().url("urlGroup2"))) + .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGroup2"))) + .addOpenApiMethodFilter(method -> !Objects.equals(method.getName(), "group2Filtered")) + .build(); + } + + @Bean + public GroupedOpenApi group3(GroupedOpenApi.Builder builder) { + return builder + .group("group3") + .addOpenApiCustomiser(openApi -> openApi.getServers().add(new Server().url("urlGroup3"))) + .addOperationCustomizer((operation, handlerMethod) -> operation.addParametersItem(new HeaderParameter().name("headerGroup3"))) + .addOpenApiMethodFilter(method -> !Objects.equals(method.getName(), "group3Filtered")) + .build(); + } + + } + + @Test + public void testGroup1() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL + "/group1")) + .andExpect(status().isOk()) + .andExpect(content().json(getContent("results/app184-1.json"), true)); + } + + @Test + public void testGroup2() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL + "/group2")) + .andExpect(status().isOk()) + .andExpect(content().json(getContent("results/app184-2.json"), true)); + } + + @Test + public void testGroup3() throws Exception { + mockMvc.perform(get(Constants.DEFAULT_API_DOCS_URL + "/group3")) + .andExpect(status().isOk()) + .andExpect(content().json(getContent("results/app184-3.json"), true)); + } + +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/app184-1.json b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-1.json new file mode 100644 index 000000000..5254e3582 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-1.json @@ -0,0 +1,97 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/app184-2.json b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-2.json new file mode 100644 index 000000000..79d588188 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-2.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlGroup2" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup2", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/app184-3.json b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-3.json new file mode 100644 index 000000000..fd621e084 --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/app184-3.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlGroup3" + } + ], + "paths": { + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/beanFiltered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "beanFiltered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerGroup3", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file diff --git a/springdoc-openapi-webmvc-core/src/test/resources/results/app184.json b/springdoc-openapi-webmvc-core/src/test/resources/results/app184.json new file mode 100644 index 000000000..771d9dbac --- /dev/null +++ b/springdoc-openapi-webmvc-core/src/test/resources/results/app184.json @@ -0,0 +1,112 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost", + "description": "Generated server url" + }, + { + "url": "urlGlobalBean" + }, + { + "url": "urlBean" + } + ], + "paths": { + "/group3Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group3Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group2Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group2Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/group1Filtered": { + "get": { + "tags": [ + "hello-controller" + ], + "operationId": "group1Filtered", + "parameters": [ + { + "name": "headerGlobalBean", + "in": "header" + }, + { + "name": "headerBean", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + } + }, + "components": {} +} \ No newline at end of file