Skip to content

Commit bb72a4a

Browse files
vpavicsnicoll
authored andcommitted
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
1 parent 32102c6 commit bb72a4a

File tree

9 files changed

+164
-7
lines changed

9 files changed

+164
-7
lines changed

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

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,40 @@
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.ConfigurableListableBeanFactory;
26+
import org.springframework.beans.factory.config.ConstructorArgumentValues;
27+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
28+
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
29+
import org.springframework.beans.factory.support.RootBeanDefinition;
2130
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2231
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
2332
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2433
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
34+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2535
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
2636
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
2737
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
2838
import org.springframework.boot.context.properties.EnableConfigurationProperties;
39+
import org.springframework.boot.context.properties.bind.Bindable;
40+
import org.springframework.boot.context.properties.bind.Binder;
2941
import org.springframework.boot.web.servlet.ServletRegistrationBean;
3042
import org.springframework.context.ApplicationContext;
43+
import org.springframework.context.ApplicationContextAware;
3144
import org.springframework.context.annotation.Bean;
3245
import org.springframework.context.annotation.Configuration;
46+
import org.springframework.core.io.Resource;
47+
import org.springframework.util.StringUtils;
3348
import org.springframework.ws.config.annotation.EnableWs;
3449
import org.springframework.ws.config.annotation.WsConfigurationSupport;
3550
import org.springframework.ws.transport.http.MessageDispatcherServlet;
51+
import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;
52+
import org.springframework.xml.xsd.SimpleXsdSchema;
3653

3754
/**
3855
* {@link EnableAutoConfiguration Auto-configuration} for Spring Web Services.
@@ -72,10 +89,76 @@ public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServle
7289
return registration;
7390
}
7491

92+
@Bean
93+
@ConditionalOnProperty(prefix = "spring.webservices", name = "wsdl-locations")
94+
public static WsdlDefinitionBeanFactoryPostProcessor wsdlDefinitionBeanFactoryPostProcessor() {
95+
return new WsdlDefinitionBeanFactoryPostProcessor();
96+
}
97+
7598
@Configuration
7699
@EnableWs
77100
protected static class WsConfiguration {
78101

79102
}
80103

104+
private static class WsdlDefinitionBeanFactoryPostProcessor
105+
implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {
106+
107+
private ApplicationContext applicationContext;
108+
109+
@Override
110+
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
111+
throws BeansException {
112+
Binder binder = Binder.get(this.applicationContext.getEnvironment());
113+
List<String> wsdlLocations = binder
114+
.bind("spring.webservices.wsdl-locations",
115+
Bindable.listOf(String.class))
116+
.orElse(Collections.emptyList());
117+
for (String wsdlLocation : wsdlLocations) {
118+
registerBeans(wsdlLocation, "*.wsdl", SimpleWsdl11Definition.class, registry);
119+
registerBeans(wsdlLocation, "*.xsd", SimpleXsdSchema.class, registry);
120+
}
121+
}
122+
123+
@Override
124+
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
125+
throws BeansException {
126+
}
127+
128+
@Override
129+
public void setApplicationContext(ApplicationContext applicationContext)
130+
throws BeansException {
131+
this.applicationContext = applicationContext;
132+
}
133+
134+
private void registerBeans(String location, String pattern, Class<?> type,
135+
BeanDefinitionRegistry registry) {
136+
Resource[] resources = new Resource[] {};
137+
try {
138+
resources = this.applicationContext
139+
.getResources(ensureTrailingSlash(location) + pattern);
140+
}
141+
catch (IOException ignored) {
142+
}
143+
for (Resource resource : resources) {
144+
RootBeanDefinition beanDefinition = new RootBeanDefinition(type);
145+
ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues();
146+
constructorArguments.addIndexedArgumentValue(0, resource);
147+
beanDefinition.setConstructorArgumentValues(constructorArguments);
148+
149+
registry.registerBeanDefinition(
150+
StringUtils.stripFilenameExtension(resource.getFilename()),
151+
beanDefinition);
152+
}
153+
}
154+
155+
private static String ensureTrailingSlash(String path) {
156+
if (!path.endsWith("/")) {
157+
return path + "/";
158+
}
159+
return path;
160+
}
161+
162+
}
163+
81164
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,6 +1183,11 @@
11831183
{
11841184
"name": "spring.thymeleaf.suffix",
11851185
"defaultValue": ".html"
1186+
},
1187+
{
1188+
"name": "spring.webservices.wsdl-locations",
1189+
"type": "java.util.List<java.lang.String>",
1190+
"description": "Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans."
11861191
}
11871192
],"hints": [
11881193
{

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import org.springframework.boot.web.servlet.ServletRegistrationBean;
2727
import org.springframework.context.ApplicationContext;
2828
import org.springframework.test.util.ReflectionTestUtils;
29+
import org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition;
30+
import org.springframework.xml.xsd.SimpleXsdSchema;
2931

3032
import static org.assertj.core.api.Assertions.assertThat;
3133

@@ -90,6 +92,18 @@ public void customInitParameters() {
9092
.containsEntry("key2", "value2"));
9193
}
9294

95+
@Test
96+
public void withWsdlBeans() {
97+
this.contextRunner
98+
.withPropertyValues("spring.webservices.wsdl-locations=classpath:/wsdl")
99+
.run(context -> {
100+
assertThat(context.getBeansOfType(SimpleWsdl11Definition.class))
101+
.hasSize(1).containsKey("service");
102+
assertThat(context.getBeansOfType(SimpleXsdSchema.class)).hasSize(1)
103+
.containsKey("types");
104+
});
105+
}
106+
93107
private Collection<String> getUrlMappings(ApplicationContext context) {
94108
return getServletRegistrationBean(context).getUrlMappings();
95109
}
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: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,7 @@ content into your application; rather pick only the properties that you need.
472472
spring.webservices.path=/services # Path that serves as the base URI for the services.
473473
spring.webservices.servlet.init= # Servlet init parameters to pass to Spring Web Services.
474474
spring.webservices.servlet.load-on-startup=-1 # Load on startup priority of the Spring Web Services servlet.
475+
spring.webservices.wsdl-locations= # Comma-separated list of locations of WSDLs and accompanying XSDs to be exposed as beans.
475476
476477
477478
[[common-application-properties-security]]

spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6560,6 +6560,11 @@ your `Endpoints`.
65606560
The {spring-webservices-reference}[Spring Web Services features] can be easily accessed
65616561
via the `spring-boot-starter-webservices` module.
65626562

6563+
Spring Boot can also automatically expose your WSDLs and XSDs using
6564+
`spring.webservices.wsdl-locations` configuration property. For the detected WSDL and XSD
6565+
files Boot will register beans of type `SimpleWsdl11Definition` and `SimpleXsdSchema`,
6566+
respectively.
6567+
65636568

65646569

65656570
[[boot-features-developing-auto-configuration]]

spring-boot-samples/spring-boot-sample-webservices/src/main/java/sample/webservices/WebServiceConfig.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,8 @@
1818

1919
import org.springframework.context.annotation.Bean;
2020
import org.springframework.context.annotation.Configuration;
21-
import org.springframework.core.io.ClassPathResource;
2221
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
2322
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
24-
import org.springframework.xml.xsd.SimpleXsdSchema;
2523
import org.springframework.xml.xsd.XsdSchema;
2624

2725
@Configuration
@@ -37,9 +35,4 @@ public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema
3735
return wsdl;
3836
}
3937

40-
@Bean
41-
public XsdSchema countriesSchema() {
42-
return new SimpleXsdSchema(new ClassPathResource("META-INF/schemas/hr.xsd"));
43-
}
44-
4538
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
spring.webservices.wsdl-locations=classpath:META-INF/schemas/

0 commit comments

Comments
 (0)