I'm trying to upgrade a project that makes use of org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean in Spring Boot 2.7.5 to Spring Boot 3. Here's the declaration of my bean:
@Bean
public JaxWsPortProxyFactoryBean myJaxWsClient() {
JaxWsPortProxyFactoryBean jaxWsPortProxyFactoryBean = new JaxWsPortProxyFactoryBean();
jaxWsPortProxyFactoryBean.setJaxWsService(new My_Service());
jaxWsPortProxyFactoryBean.setWsdlDocumentUrl(Thread.currentThread().getContextClassLoader().getResource("META-INF/my.wsdl"));
jaxWsPortProxyFactoryBean.setNamespaceUri("urn:net:something");
jaxWsPortProxyFactoryBean.setServiceName("MyService");
jaxWsPortProxyFactoryBean.setServiceInterface(My.class);
jaxWsPortProxyFactoryBean.setEndpointAddress("http://someuri:7979/myservice");
jaxWsPortProxyFactoryBean.setUsername("username");
jaxWsPortProxyFactoryBean.setPassword("password");
return jaxWsPortProxyFactoryBean;
}
However, org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean doesn't seem to be available in Spring Boot 3, or it has moved to another library.
My question is: How do I use JaxWsPortProxyFactoryBean in Spring Boot 3, or how do I migrate to a more modern alternative (if available)?
This class, as many others, has been removed in Spring Framework 6 (which is used by Spring Boot 3). It has been documented by this Github ticket and this commit. The old style remoting support (due to vulnerabilities and better options available) has been removed from the core library.
For the JAX-WS part you probably want to use something like Apache CXF in the current day and age, which would allow for a dynamic proxy. Another option is to implement the client yourself using Spring Web Services
Jakarta JAXWS-RI is also an option: You generate MyService and MyPort using the jaxws-maven-plugin. Then you set it up using Spring, assuming you have written a MyConfigProperties class to access application.properties.
In a MyConfig class which sets up the beans and takes the MyConfigProperties, also adding SSL support for good measure:
@Configuration
public class MyConfig {
public MyConfig(MyConfigProperties myConfigProperties) {
this.myConfigProperties = myConfigProperties;
}
@Bean
public MyService myService() {
try {
URL wsdlLocation = this.getClass().getResource("/META-INF/wsdl/my.wsdl");
return new MyService(wsdlLocation); // may pass features here
} catch (Exception e) {
throw(new IllegalStateException(e);
}
}
@Bean
public KeyStoreFactoryBean keyStore() {
KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean();
Resource location = new ClassPathResource(myConfigProperties.getKeystoreLocation());
keyStoreFactoryBean.setLocation(location);
keyStoreFactoryBean.setPassword(myConfigProperties.getKeystorePassword());
return keyStoreFactoryBean;
}
@Bean
public KeyStoreFactoryBean trustStore() {
KeyStoreFactoryBean keyStoreFactoryBean = new KeyStoreFactoryBean();
Resource location = new ClassPathResource(myConfigProperties.getTruststoreLocation());
keyStoreFactoryBean.setLocation(location);
keyStoreFactoryBean.setPassword(myConfigProperties.getTruststorePassword());
return keyStoreFactoryBean;
}
@Bean
public TrustManagersFactoryBean trustManagers(KeyStore trustStore) {
TrustManagersFactoryBean trustManagersFactoryBean = new TrustManagersFactoryBean();
trustManagersFactoryBean.setKeyStore(trustStore);
return trustManagersFactoryBean;
}
@Bean
public KeyManagersFactoryBean keyManagers(KeyStore keyStore) {
KeyManagersFactoryBean keyManagersFactoryBean = new KeyManagersFactoryBean();
keyManagersFactoryBean.setKeyStore(keyStore);
keyManagersFactoryBean.setPassword(props.getKeystorePassword());
return keyManagersFactoryBean;
}
@Bean
public SSLSocketFactory sslSocketFactory(TrustManager[] trustManagers, KeyManager[] keyManagers) throws Exception {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, trustManagers, new SecureRandom());
return sslContext.getSocketFactory();
}
}
In your client implementation:
@Component
public class MyClient {
public MyClient(MyService myService, MyConfigProperties props,
SSLSocketFactory sslSocketFactory) {
this.myPort = myService.getMyPort();
this.props = props;
this.sslSocketFactory = sslSocketFactory;
}
public MyResult callEndpoint() {
BindingProvider bindingProvider = (BindingProvider) msgBoxPort;
Map<String, Object> requestContext = bindingProvider.getRequestContext();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, props.getWebserviceUri());
requestContext.put(JAXWSProperties.SSL_SOCKET_FACTORY, sslSocketFactory);
return myPort.callEndpoint();
}
}
For the code generation you might be interested in https://stackoverflow.com/a/77465064/743507, I just recently went through the hassle to build a SOAP client for a rather complex WSDL, where I had to download a lot of schema files and needed a catalog to point the jaxws-maven-plugin to the downloaded stuff. This is generally a good idea, because you don't want your client to fail during startup if the target service is not available (or doesn't publish its WSDL properly).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With