Skip to content

Commit abbf55d

Browse files
committed
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`/`spring.webservices.xsd-locations` properties which will search the provided locations for WSDL/XSD files and register appropriate beans.
1 parent eac4c7e commit abbf55d

File tree

6 files changed

+218
-0
lines changed

6 files changed

+218
-0
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfiguration.java

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,41 @@
1616

1717
package org.springframework.boot.autoconfigure.webservices;
1818

19+
import java.io.IOException;
20+
import java.util.Collections;
21+
import java.util.List;
1922
import java.util.Map;
2023

24+
import org.springframework.beans.BeansException;
25+
import org.springframework.beans.factory.config.BeanDefinition;
26+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
27+
import org.springframework.beans.factory.config.ConstructorArgumentValues;
28+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
29+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
30+
import org.springframework.beans.factory.support.RootBeanDefinition;
2131
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2232
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2333
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2434
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
35+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2536
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
2637
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
2738
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
2839
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40+
import org.springframework.boot.context.properties.bind.Bindable;
41+
import org.springframework.boot.context.properties.bind.Binder;
2942
import org.springframework.boot.web.servlet.ServletRegistrationBean;
3043
import org.springframework.context.ApplicationContext;
44+
import org.springframework.context.ApplicationContextAware;
3145
import org.springframework.context.annotation.Bean;
3246
import org.springframework.context.annotation.Configuration;
47+
import org.springframework.core.io.Resource;
48+
import org.springframework.util.StringUtils;
3349
import org.springframework.ws.config.annotation.EnableWs;
3450
import org.springframework.ws.config.annotation.WsConfigurationSupport;
3551
import org.springframework.ws.transport.http.MessageDispatcherServlet;
52+
import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;
53+
import org.springframework.xml.xsd.SimpleXsdSchema;
3654

3755
/**
3856
* {@link EnableAutoConfiguration Auto-configuration} for Spring Web Services.
@@ -72,10 +90,123 @@ public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServle
7290
return registration;
7391
}
7492

93+
@Bean
94+
@ConditionalOnProperty(prefix = "spring.webservices", name = "wsdl-locations")
95+
public static WsdlDefinitionBeanFactoryPostProcessor wsdlDefinitionBeanFactoryPostProcessor() {
96+
return new WsdlDefinitionBeanFactoryPostProcessor();
97+
}
98+
99+
@Bean
100+
@ConditionalOnProperty(prefix = "spring.webservices", name = "xsd-locations")
101+
public static XsdSchemaBeanFactoryPostProcessor xsdSchemaBeanFactoryPostProcessor() {
102+
return new XsdSchemaBeanFactoryPostProcessor();
103+
}
104+
105+
private static String ensureTrailingSlash(String path) {
106+
if (!path.endsWith("/")) {
107+
return path + "/";
108+
}
109+
return path;
110+
}
111+
112+
private static BeanDefinition createBeanDefinition(Resource resource, Class type) {
113+
RootBeanDefinition beanDefinition = new RootBeanDefinition(type);
114+
ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues();
115+
constructorArguments.addIndexedArgumentValue(0, resource);
116+
beanDefinition.setConstructorArgumentValues(constructorArguments);
117+
return beanDefinition;
118+
}
119+
75120
@Configuration
76121
@EnableWs
77122
protected static class WsConfiguration {
78123

79124
}
80125

126+
private static class WsdlDefinitionBeanFactoryPostProcessor
127+
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
128+
129+
private ApplicationContext applicationContext;
130+
131+
@Override
132+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
133+
throws BeansException {
134+
Binder binder = Binder.get(this.applicationContext.getEnvironment());
135+
List<String> wsdlLocations = binder
136+
.bind("spring.webservices.wsdl-locations",
137+
Bindable.listOf(String.class))
138+
.orElse(Collections.emptyList());
139+
for (String wsdlLocation : wsdlLocations) {
140+
Resource[] wsdlResources = new Resource[] {};
141+
try {
142+
wsdlResources = this.applicationContext
143+
.getResources(ensureTrailingSlash(wsdlLocation) + "*.wsdl");
144+
}
145+
catch (IOException ignored) {
146+
}
147+
for (Resource wsdlResource : wsdlResources) {
148+
registry.registerBeanDefinition(
149+
StringUtils
150+
.stripFilenameExtension(wsdlResource.getFilename()),
151+
createBeanDefinition(wsdlResource,
152+
SimpleWsdl11Definition.class));
153+
}
154+
}
155+
}
156+
157+
@Override
158+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
159+
throws BeansException {
160+
}
161+
162+
@Override
163+
public void setApplicationContext(ApplicationContext applicationContext)
164+
throws BeansException {
165+
this.applicationContext = applicationContext;
166+
}
167+
168+
}
169+
170+
private static class XsdSchemaBeanFactoryPostProcessor
171+
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
172+
173+
private ApplicationContext applicationContext;
174+
175+
@Override
176+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
177+
throws BeansException {
178+
Binder binder = Binder.get(this.applicationContext.getEnvironment());
179+
List<String> xsdLocations = binder
180+
.bind("spring.webservices.xsd-locations",
181+
Bindable.listOf(String.class))
182+
.orElse(Collections.emptyList());
183+
for (String xsdLocation : xsdLocations) {
184+
Resource[] xsdResources = new Resource[] {};
185+
try {
186+
xsdResources = this.applicationContext
187+
.getResources(ensureTrailingSlash(xsdLocation) + "*.xsd");
188+
}
189+
catch (IOException ignored) {
190+
}
191+
for (Resource xsdResource : xsdResources) {
192+
registry.registerBeanDefinition(
193+
StringUtils.stripFilenameExtension(xsdResource.getFilename()),
194+
createBeanDefinition(xsdResource, SimpleXsdSchema.class));
195+
}
196+
}
197+
}
198+
199+
@Override
200+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
201+
throws BeansException {
202+
}
203+
204+
@Override
205+
public void setApplicationContext(ApplicationContext applicationContext)
206+
throws BeansException {
207+
this.applicationContext = applicationContext;
208+
}
209+
210+
}
211+
81212
}

spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,16 @@
388388
"type": "java.lang.Boolean",
389389
"description": "Enable the connection status view for supported providers.",
390390
"defaultValue": false
391+
},
392+
{
393+
"name": "spring.webservices.wsdl-locations",
394+
"type": "java.util.List<java.lang.String>",
395+
"description": "Comma-separated list of locations of WSDLs to be exposed as beans."
396+
},
397+
{
398+
"name": "spring.webservices.xsd-locations",
399+
"type": "java.util.List<java.lang.String>",
400+
"description": "Comma-separated list of locations of XSDs to be exposed as beans."
391401
}
392402
],"hints": [
393403
{

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/webservices/WebServicesAutoConfigurationTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.springframework.boot.web.servlet.ServletRegistrationBean;
2929
import org.springframework.context.ApplicationContext;
3030
import org.springframework.test.util.ReflectionTestUtils;
31+
import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;
32+
import org.springframework.xml.xsd.SimpleXsdSchema;
3133

3234
import static org.assertj.core.api.Assertions.assertThat;
3335

@@ -98,6 +100,24 @@ public void customInitParameters() {
98100
.containsEntry("key2", "value2"));
99101
}
100102

103+
@Test
104+
public void withWsdlBeans() {
105+
this.contextRunner
106+
.withPropertyValues("spring.webservices.wsdl-locations=classpath:/wsdl")
107+
.run((context -> assertThat(
108+
context.getBeansOfType(SimpleWsdl11Definition.class)).hasSize(1)
109+
.containsKey("service")));
110+
}
111+
112+
@Test
113+
public void withXsdBeans() {
114+
this.contextRunner
115+
.withPropertyValues("spring.webservices.xsd-locations=classpath:/xsd")
116+
.run((context -> assertThat(
117+
context.getBeansOfType(SimpleXsdSchema.class)).hasSize(1)
118+
.containsKey("types")));
119+
}
120+
101121
private Collection<String> getUrlMappings(ApplicationContext context) {
102122
return getServletRegistrationBean(context).getUrlMappings();
103123
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
3+
xmlns:tns="http://www.springframework.org/spring-ws/wsdl"
4+
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/"
5+
targetNamespace="http://www.springframework.org/spring-ws/wsdl">
6+
7+
<wsdl:types>
8+
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
9+
targetNamespace="http://www.springframework.org/spring-ws/wsdl">
10+
<xsd:element name="request" type="xsd:string"/>
11+
<xsd:element name="response" type="xsd:string"/>
12+
</xsd:schema>
13+
</wsdl:types>
14+
15+
<wsdl:message name="responseMessage">
16+
<wsdl:part name="body" element="tns:response"/>
17+
</wsdl:message>
18+
19+
<wsdl:message name="requestMessage">
20+
<wsdl:part name="body" element="tns:request"/>
21+
</wsdl:message>
22+
23+
<wsdl:portType name="portType">
24+
<wsdl:operation name="operation">
25+
<wsdl:input message="tns:requestMessage" name="request"/>
26+
<wsdl:output message="tns:responseMessage" name="response"/>
27+
</wsdl:operation>
28+
</wsdl:portType>
29+
30+
<wsdl:binding name="binding" type="tns:portType">
31+
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
32+
<wsdl:operation name="operation">
33+
<wsdlsoap:operation soapAction=""/>
34+
<wsdl:input name="request">
35+
<wsdlsoap:body use="literal"/>
36+
</wsdl:input>
37+
<wsdl:output name="response">
38+
<wsdlsoap:body use="literal"/>
39+
</wsdl:output>
40+
</wsdl:operation>
41+
</wsdl:binding>
42+
43+
<wsdl:service name="service">
44+
<wsdl:port binding="tns:binding" name="port">
45+
<wsdlsoap:address location="/services"/>
46+
</wsdl:port>
47+
</wsdl:service>
48+
</wsdl:definitions>
49+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<schema xmlns="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
3+
targetNamespace="http://www.springframework.org/spring-ws/wsdl/schemas">
4+
<element name="request" type="string"/>
5+
<element name="response" type="string"/>
6+
</schema>

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ content into your application; rather pick only the properties that you need.
463463
spring.webservices.path=/services # Path that serves as the base URI for the services.
464464
spring.webservices.servlet.init= # Servlet init parameters to pass to Spring Web Services.
465465
spring.webservices.servlet.load-on-startup=-1 # Load on startup priority of the Spring Web Services servlet.
466+
spring.webservices.wsdl-locations= # Comma-separated list of locations of WSDLs to be exposed as beans.
467+
spring.webservices.xsd-locations= # Comma-separated list of locations of XSDs to be exposed as beans.
466468
467469
468470
[[common-application-properties-security]]

0 commit comments

Comments
 (0)