From bb72a4abe11dc381b8bc01dec837460e294ca2b3 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Thu, 29 Jun 2017 13:36:14 +0200 Subject: [PATCH 1/2] Add support for Spring WS auto WSDL/XSD exposure This commit adds support for auto-configuration of Spring WS automatic WSDL and XSD exposure i.e. registration of `WsdlDefinition` and `XsdDefinition` beans. The bean registration is triggered by configuring `spring.webservices.wsdl-locations` property which will search the provided locations for WSDL/XSD files and register appropriate beans. See gh-9635 --- .../WebServicesAutoConfiguration.java | 83 +++++++++++++++++++ ...itional-spring-configuration-metadata.json | 5 ++ .../WebServicesAutoConfigurationTests.java | 14 ++++ .../src/test/resources/wsdl/service.wsdl | 49 +++++++++++ .../src/test/resources/wsdl/types.xsd | 6 ++ .../appendix-application-properties.adoc | 1 + .../main/asciidoc/spring-boot-features.adoc | 5 ++ .../sample/webservices/WebServiceConfig.java | 7 -- .../src/main/resources/application.properties | 1 + 9 files changed, 164 insertions(+), 7 deletions(-) create mode 100644 spring-boot-autoconfigure/src/test/resources/wsdl/service.wsdl create mode 100644 spring-boot-autoconfigure/src/test/resources/wsdl/types.xsd create mode 100644 spring-boot-samples/spring-boot-sample-webservices/src/main/resources/application.properties 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 9474c1cc5df..26635733b3b 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 class WebServicesAutoConfiguration { 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 cdc88b8e070..833e330458a 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 6225efc4644..f37c41f144e 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.test.context.runner.WebApplicationContextRunner; 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 class WebServicesAutoConfigurationTests { .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 00000000000..19c36925441 --- /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 00000000000..88e0c486595 --- /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 443126242e6..6f7c6a968a1 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 77d54c67395..d912afd140e 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6560,6 +6560,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 4424511505e..9de68258ff3 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 @@ package sample.webservices; 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 class WebServiceConfig extends WsConfigurerAdapter { 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 00000000000..2453faa0be4 --- /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/ From 15de6531a527602cd5d05c6a9e15e175c93885c3 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 25 Sep 2017 15:20:55 +0200 Subject: [PATCH 2/2] Polish "Add support for Spring WS auto WSDL/XSD exposure" Closes gh-9635 --- .../WebServicesAutoConfiguration.java | 31 ++++++++++--------- .../main/asciidoc/spring-boot-features.adoc | 12 ++++--- 2 files changed, 24 insertions(+), 19 deletions(-) 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 26635733b3b..f4660fa738a 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 @@ -106,6 +106,11 @@ public class WebServicesAutoConfiguration { private ApplicationContext applicationContext; + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { @@ -125,33 +130,29 @@ public class WebServicesAutoConfiguration { 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) { + for (Resource resource : getResources(location, pattern)) { RootBeanDefinition beanDefinition = new RootBeanDefinition(type); ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues(); constructorArguments.addIndexedArgumentValue(0, resource); beanDefinition.setConstructorArgumentValues(constructorArguments); - registry.registerBeanDefinition( StringUtils.stripFilenameExtension(resource.getFilename()), beanDefinition); } } + private Resource[] getResources(String location, String pattern) { + try { + return this.applicationContext + .getResources(ensureTrailingSlash(location) + pattern); + } + catch (IOException e) { + return new Resource[0]; + } + } + private static String ensureTrailingSlash(String path) { if (!path.endsWith("/")) { return path + "/"; 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 d912afd140e..7186bc52569 100644 --- a/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -6560,10 +6560,14 @@ 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. +`SimpleWsdl11Definition` and `SimpleXsdSchema` beans can be automatically created for your +WSDLs and XSDs respectively. To do so, configure their location: + + +[source,properties,indent=0] +---- + spring.webservices.wsdl-locations=classpath:/wsdl +----