diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java index 9474c1cc5df7..26635733b3b1 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java @@ -16,23 +16,40 @@ package org.springframework.boot.autoconfigure.webservices; +import java.io.IOException; +import java.util.Collections; +import java.util.List; import java.util.Map; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.ConstructorArgumentValues; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.Resource; +import org.springframework.util.StringUtils; import org.springframework.ws.config.annotation.EnableWs; import org.springframework.ws.config.annotation.WsConfigurationSupport; import org.springframework.ws.transport.http.MessageDispatcherServlet; +import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition; +import org.springframework.xml.xsd.SimpleXsdSchema; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Web Services. @@ -72,10 +89,76 @@ public ServletRegistrationBean messageDispatcherServle return registration; } + @Bean + @ConditionalOnProperty(prefix = "spring.webservices", name = "wsdl-locations") + public static WsdlDefinitionBeanFactoryPostProcessor wsdlDefinitionBeanFactoryPostProcessor() { + return new WsdlDefinitionBeanFactoryPostProcessor(); + } + @Configuration @EnableWs protected static class WsConfiguration { } + private static class WsdlDefinitionBeanFactoryPostProcessor + implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { + + private ApplicationContext applicationContext; + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) + throws BeansException { + Binder binder = Binder.get(this.applicationContext.getEnvironment()); + List wsdlLocations = binder + .bind("spring.webservices.wsdl-locations", + Bindable.listOf(String.class)) + .orElse(Collections.emptyList()); + for (String wsdlLocation : wsdlLocations) { + registerBeans(wsdlLocation, "*.wsdl", SimpleWsdl11Definition.class, registry); + registerBeans(wsdlLocation, "*.xsd", SimpleXsdSchema.class, registry); + } + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + this.applicationContext = applicationContext; + } + + private void registerBeans(String location, String pattern, Class type, + BeanDefinitionRegistry registry) { + Resource[] resources = new Resource[] {}; + try { + resources = this.applicationContext + .getResources(ensureTrailingSlash(location) + pattern); + } + catch (IOException ignored) { + } + for (Resource resource : resources) { + RootBeanDefinition beanDefinition = new RootBeanDefinition(type); + ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues(); + constructorArguments.addIndexedArgumentValue(0, resource); + beanDefinition.setConstructorArgumentValues(constructorArguments); + + registry.registerBeanDefinition( + StringUtils.stripFilenameExtension(resource.getFilename()), + beanDefinition); + } + } + + private static String ensureTrailingSlash(String path) { + if (!path.endsWith("/")) { + return path + "/"; + } + return path; + } + + } + } diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index cdc88b8e0706..833e330458ac 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1183,6 +1183,11 @@ { "name": "spring.thymeleaf.suffix", "defaultValue": ".html" + }, + { + "name": "spring.webservices.wsdl-locations", + "type": "java.util.List", + "description": "Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans." } ],"hints": [ { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java index 6225efc4644b..f37c41f144e7 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java @@ -26,6 +26,8 @@ import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.ApplicationContext; import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition; +import org.springframework.xml.xsd.SimpleXsdSchema; import static org.assertj.core.api.Assertions.assertThat; @@ -90,6 +92,18 @@ public void customInitParameters() { .containsEntry("key2", "value2")); } + @Test + public void withWsdlBeans() { + this.contextRunner + .withPropertyValues("spring.webservices.wsdl-locations=classpath:/wsdl") + .run(context -> { + assertThat(context.getBeansOfType(SimpleWsdl11Definition.class)) + .hasSize(1).containsKey("service"); + assertThat(context.getBeansOfType(SimpleXsdSchema.class)).hasSize(1) + .containsKey("types"); + }); + } + private Collection getUrlMappings(ApplicationContext context) { return getServletRegistrationBean(context).getUrlMappings(); } diff --git a/spring-boot-autoconfigure/src/test/resources/wsdl/service.wsdl b/spring-boot-autoconfigure/src/test/resources/wsdl/service.wsdl new file mode 100644 index 000000000000..19c369254419 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/wsdl/service.wsdl @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-boot-autoconfigure/src/test/resources/wsdl/types.xsd b/spring-boot-autoconfigure/src/test/resources/wsdl/types.xsd new file mode 100644 index 000000000000..88e0c4865958 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/wsdl/types.xsd @@ -0,0 +1,6 @@ + + + + + diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 111f722999ef..e8c4b873adfc 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -472,6 +472,7 @@ content into your application; rather pick only the properties that you need. spring.webservices.path=/services # Path that serves as the base URI for the services. spring.webservices.servlet.init= # Servlet init parameters to pass to Spring Web Services. spring.webservices.servlet.load-on-startup=-1 # Load on startup priority of the Spring Web Services servlet. + spring.webservices.wsdl-locations= # Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans. [[common-application-properties-security]] diff --git a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 76c84040c4a0..0b16c5c87e1e 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6524,6 +6524,11 @@ your `Endpoints`. The {spring-webservices-reference}[Spring Web Services features] can be easily accessed via the `spring-boot-starter-webservices` module. +Spring Boot can also automatically expose your WSDLs and XSDs using +`spring.webservices.wsdl-locations` configuration property. For the detected WSDL and XSD +files Boot will register beans of type `SimpleWsdl11Definition` and `SimpleXsdSchema`, +respectively. + [[boot-features-developing-auto-configuration]] diff --git a/spring-boot-samples/spring-boot-sample-webservices/src/main/java/sample/webservices/WebServiceConfig.java b/spring-boot-samples/spring-boot-sample-webservices/src/main/java/sample/webservices/WebServiceConfig.java index 4424511505e9..9de68258ff39 100644 --- a/spring-boot-samples/spring-boot-sample-webservices/src/main/java/sample/webservices/WebServiceConfig.java +++ b/spring-boot-samples/spring-boot-sample-webservices/src/main/java/sample/webservices/WebServiceConfig.java @@ -18,10 +18,8 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.ClassPathResource; import org.springframework.ws.config.annotation.WsConfigurerAdapter; import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition; -import org.springframework.xml.xsd.SimpleXsdSchema; import org.springframework.xml.xsd.XsdSchema; @Configuration @@ -37,9 +35,4 @@ public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema return wsdl; } - @Bean - public XsdSchema countriesSchema() { - return new SimpleXsdSchema(new ClassPathResource("META-INF/schemas/hr.xsd")); - } - } diff --git a/spring-boot-samples/spring-boot-sample-webservices/src/main/resources/application.properties b/spring-boot-samples/spring-boot-sample-webservices/src/main/resources/application.properties new file mode 100644 index 000000000000..2453faa0be44 --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-webservices/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.webservices.wsdl-locations=classpath:META-INF/schemas/