Search code examples
javaspringspring-ws

Spring-ws javaconfig location transformation


I'm attempting to setup webservices project (currently SOAP -but will add REST eventually), using Java-Config. Unfortunately, I haven't been able to automatically expose the WSDL (supposedly, Spring can generate it based on the XSDs and expose it).

The only documentation I've found uses xml configuration when defining the servlet (web.xml).

<init-param>
    <param-name>transformWsdlLocations</param-name>
    <param-value>true</param-value>
</init-param>

How do you accomplish this using Java-config?

WebApplicationInitializer

public class WebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

/**
 * {@inheritDoc} 
 */
@Override
protected Class<?>[] getRootConfigClasses() {

    return new Class[] {WebSecurityConfiguration.class};
}

/**
 * {@inheritDoc} 
 */
@Override
protected Class<?>[] getServletConfigClasses() {

    return new Class[] {WebServicesConfiguration.class};
}

/**
 * {@inheritDoc} 
 */
@Override
protected String[] getServletMappings() {

    // get all mappings
    return new String[] { "/" };
}

WebServicesConfiguration

@EnableWs
@Configuration
@ComponentScan("com.questsoftware")
public class WebServicesConfiguration extends WsConfigurationSupport {


@Bean
public XsdSchema schema() {

    return new SimpleXsdSchema(new ClassPathResource("lookup.xsd"));
}

@Bean
public DefaultWsdl11Definition defaultWsdl11Definition() {

    DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
    wsdl11Definition.setTargetNamespace("http://com/[mycompany]/Lookup");
    wsdl11Definition.setPortTypeName("Lookup");
    wsdl11Definition.setLocationUri("/Lookup");
    wsdl11Definition.setSchema(schema());

    return wsdl11Definition;
}

TO BE CLEAR - I also have a WebApplicationConfiguration (REST) -but I haven't added it in the WebApplicationInitializer yet (ran across this problem first).

WebApplicationConfiguration

@EnableWebMvc
@EnableAspectJAutoProxy(proxyTargetClass = true)
@Configuration
@ComponentScan("com.mycompany")
public class WebApplicationConfiguration extends WebMvcConfigurerAdapter {


/**
 * Defines {@link JdbcTemplate} as a Spring managed bean.
 * 
 * @return 
 */
@Bean
public JdbcTemplate jdbcTemplate() {

    return new JdbcTemplate(dataSource());
}

@Bean
public DataSource dataSource() {

    ...

    return dataSource;
}

/**
 * Defines a {@link ViewResolver} as a Spring managed bean.
 * 
 * @return the viewResolver
 */
@Bean
public ViewResolver viewResolver() {

    final InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/WEB-INF/pages");
    resolver.setSuffix(".jsp");

    return resolver;
}

/**
 * Registers resource handlers with Spring.
 * 
 * @param registry the {@link ResourceHandlerRegistry}
 */
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {

    registry.addResourceHandler("/view/**").addResourceLocations("/view/");
}

Reference

http://docs.spring.io/spring-ws/sites/2.0/reference/html/server.html#server-automatic-wsdl-exposure


Solution

  • I was able to come up with a solution, but I'm not entirely sure if it's the 'correct' or 'preferred' way.

    I followed the tutorial and simply defined the beans in my java-config based WebApplicationConfiguration, that were defined in the tutorials xml-based configuration. --my understanding, is that there really is no underlying difference, and you simply have to have the beans added to the Spring container, so Spring can work it's magic.

    I've updated the code above with the following changes:

    WebApplicationConfiguration

    added the following beans

    /**
     * Defines the {@link SaajSoapMessageFactory} as a Spring managed bean.
     * 
     * Note: we need a Soap implementation of a MessageFactory to create soap messages in Spring-WS.
     * 
     * @return the messageFactory
     */
    @Bean
    public SaajSoapMessageFactory messageFactory() {
    
        return new SaajSoapMessageFactory();
    }
    
    /**
     * Defines the {@link WebServiceMessageReceiverHandlerAdapter} as a Spring managed bean.
     * 
     * Note: We need to add this bean to the context in order for the DispatcherServlet to delegate to a MessageDispatcher 
     * (as opposed to Controllers).  The MessageDispatcher is necessary for Spring-WS.
     * 
     * @return the webServiceMessageReceiverHandlerAdapter
     */
    @Bean
    public WebServiceMessageReceiverHandlerAdapter webServiceMessageReceiverHandlerAdapter() {
    
        WebServiceMessageReceiverHandlerAdapter adapter = new WebServiceMessageReceiverHandlerAdapter();
        adapter.setMessageFactory(messageFactory());
    
        return adapter;
    }
    
    /**
     * Defines the {@link SimpleUrlHandlerMapping} as a Spring managed bean.
     * 
     * Note: In order for the DispatcherServlet to handle SOAP message, we were forced to add the {@link WebServiceMessageReceiverHandlerAdapter}
     * to the context. By explicitely adding that bean to the context, we are now forced to also add this bean to handle REST messages.
     * 
     * @return the simpleUrlHandlerMapping
     */
    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
    
        SimpleUrlHandlerMapping simpleUrlHandlerMapping = new SimpleUrlHandlerMapping();
        simpleUrlHandlerMapping.setDefaultHandler(messageDispatcher());
        Properties urlProperties = new Properties();
    
        urlProperties.put("Lookup.wsdl", "Lookup");
    
        simpleUrlHandlerMapping.setMappings(urlProperties);
        simpleUrlHandlerMapping.setDefaultHandler(messageDispatcher());
    
        return simpleUrlHandlerMapping;
    }
    
    /**
     * Defines the {@link SoapMessageDispatcher} as a Spring managed bean.
     * 
     * Note: Dispatches SOAP messages.
     * 
     * @return the messageDispatcher
     */
    @Bean 
    public SoapMessageDispatcher messageDispatcher() {
    
        return new SoapMessageDispatcher();
    }
    
    /**
     * Defines the {@link SimpleControllerHandlerAdapter} as a Spring managed bean.
     * 
     * Note: In order for the DispatcherServlet to handle SOAP messages, we were forced to add the {@link WebServiceMessageReceiverHandlerAdapter}
     * to the context.  By explicitely adding that bean to the context, the default adapters were not automatically added to handle 
     * standard MVC Controllers.  We must add this bean to do that.
     * 
     * @return the simpleControllerHandlerAdapter
     */
    @Bean
    public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
    
        return new SimpleControllerHandlerAdapter();
    }
    

    WebServicesConfiguration

    removed @ComponentScan("com.mycompany") - the WebApplicationConfiguration already did this for me, and in fact picks up all the beans in this configuration.

    added the following bean

    @Bean
    public WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter() {
    
        WsdlDefinitionHandlerAdapter wsdlDefinitionHandlerAdapter = new WsdlDefinitionHandlerAdapter();
        wsdlDefinitionHandlerAdapter.setTransformLocations(true);
    
        return wsdlDefinitionHandlerAdapter;
    }
    

    Note!!! - in the bean definition of WsdlDefinitionHandlerAdapter, I call the setter for transformLocations. This along with the urlMapping in the WebApplicationConfig is the key to exposing the WSDL. Of course the other beans are required, but this was the gist of the original question.