Spring-ws @Endpoint/@PayloadRoot based configuration giving 404

17,290

Wow, unbelievable - of all things, it was the access modifier on my "getTemperature()" method in TemperatureMarshallingEndpoint. It was "protected", but needed to be "public" (works like a charm after making the change!)

Share:
17,290
Nick
Author by

Nick

Updated on July 23, 2022

Comments

  • Nick
    Nick almost 2 years

    Really stumped on this one - trying to utilize Spring-ws's @Endpoint and @PayloadRoot to automagically stand up some WSDL endpoints, but I keep getting a 404 (deploying into Tomcat 7.0.54). I've scoured this thing looking for naming inconsistencies (seems to be the most common cause of problems), but am finding nothing!

    pom.xml:

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-core-tiger</artifactId>
            <version>1.5.2</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.9</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.castor</groupId>
            <artifactId>castor</artifactId>
            <version>1.2</version>
        </dependency>
    

    Web.xml:

    <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                            http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <servlet>
        <servlet-name>weather</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>weather</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    </web-app>
    

    weather-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
    <bean id="weatherService" class="com.nick.example.weather.WeatherServiceImpl"/>
    
    <bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
    
    <bean id="temperatureEndpoint" class="com.nick.example.weather.TemperatureMarshallingEndpoint">
        <property name="weatherService" ref="weatherService"/>
    </bean>
    
    <bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
        <property name="marshaller" ref="marshaller"/>
        <property name="unmarshaller" ref="marshaller"/>
    </bean>
    
    <bean id="marshaller" class="org.springframework.oxm.castor.CastorMarshaller">
        <property name="mappingLocation" value="classpath:mapping.xml"/>
    </bean>
    
    <bean id="temperature" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
        <property name="builder">
            <bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
                <property name="schema" value="/WEB-INF/temperature.xsd"/>
                <property name="portTypeName" value="Weather"/>
                <property name="locationUri" value="http://localhost:8080/weather/services"/>
            </bean>
        </property>
    </bean>
    </beans>
    

    temperature.xsd

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema attributeFormDefault="unqualified"
           elementFormDefault="qualified"
           targetNamespace="http://nick.com/weather/schemas"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
    
    <xs:element name="GetTemperaturesRequest">
    <xs:complexType>
      <xs:sequence>
        <xs:element type="xs:string" name="city"/>
        <xs:element type="xs:date" name="date" maxOccurs="5" minOccurs="1"/>
      </xs:sequence>
    </xs:complexType>
    </xs:element>
    <xs:element name="GetTemperaturesResponse">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="TemperatureInfo" maxOccurs="5" minOccurs="1">
          <xs:complexType>
            <xs:sequence>
              <xs:element type="xs:float" name="min"/>
              <xs:element type="xs:float" name="max"/>
              <xs:element type="xs:float" name="average"/>
            </xs:sequence>
            <xs:attribute type="xs:string" name="city" use="optional"/>
            <xs:attribute type="xs:date" name="date" use="optional"/>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
    </xs:element>
    </xs:schema>
    

    TemperatureMarshallingEndpoint.java:

    package com.nick.example.weather;
    
    import org.springframework.ws.server.endpoint.annotation.Endpoint;
    import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
    
    import java.util.List;
    
    @Endpoint
    public class TemperatureMarshallingEndpoint {
    
    private static final String namespaceUri = "http://nick.com/weather/schemas";
    
    private WeatherService weatherService;
    
    public void setWeatherService(WeatherService weatherService) {
        this.weatherService = weatherService;
    }
    
    @PayloadRoot(
            localPart = "GetTemperaturesRequest",
            namespace = namespaceUri)
    protected GetTemperaturesResponse getTemperature(GetTemperaturesRequest request) {
        List<TemperatureInfo> temperatures = weatherService.getTemperatures(request.getCity(), request.getDates());
        return new GetTemperaturesResponse(temperatures);
    }
    }
    

    I'm deploying to Tomcat right off the root ("/") - no errors, deploys fine. Below is the resulting wsdl, but one interesting note is that I can hit it with any URL starting with http://localhost:8080 and ending with "/temperature.wsdl". i.e. http://localhost:8080/weather/services/temperature.wsdl nets me the same wsdl as http://localhost:8080/blah/blah/blah/temperature.wsdl

    WSDL:

    <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:schema="http://nick.com/weather/schemas" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://nick.com/weather/schemas">
    <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://nick.com/weather/schemas">
    <xs:element name="GetTemperaturesRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="city" type="xs:string"/>
                <xs:element maxOccurs="5" minOccurs="1" name="date" type="xs:date"/>
            </xs:sequence>
         </xs:complexType>
    </xs:element>
    <xs:element name="GetTemperaturesResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element maxOccurs="5" minOccurs="1" name="TemperatureInfo">
                     <xs:complexType>
                         <xs:sequence>
                              <xs:element name="min" type="xs:float"/>
                              <xs:element name="max" type="xs:float"/>
                              <xs:element name="average" type="xs:float"/>
                         </xs:sequence>
                         <xs:attribute name="city" type="xs:string" use="optional"/>
                         <xs:attribute name="date" type="xs:date" use="optional"/>
                     </xs:complexType>
                </xs:element> 
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    </xs:schema>
    </wsdl:types>
    <wsdl:message name="GetTemperaturesRequest">
        <wsdl:part element="schema:GetTemperaturesRequest" name="GetTemperaturesRequest"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="GetTemperaturesResponse">
        <wsdl:part element="schema:GetTemperaturesResponse" name="GetTemperaturesResponse"></wsdl:part>
    </wsdl:message>
    <wsdl:portType name="Weather">
        <wsdl:operation name="GetTemperatures">
            <wsdl:input message="schema:GetTemperaturesRequest" name="GetTemperaturesRequest"></wsdl:input>
            <wsdl:output message="schema:GetTemperaturesResponse" name="GetTemperaturesResponse"></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="WeatherBinding" type="schema:Weather">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="GetTemperatures">
            <soap:operation soapAction=""/>
            <wsdl:input name="GetTemperaturesRequest">
                <soap:body use="literal"/>
            </wsdl:input>
            <wsdl:output name="GetTemperaturesResponse">
                <soap:body use="literal"/>
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="WeatherService">
        <wsdl:port binding="schema:WeatherBinding" name="WeatherPort">
            <soap:address location="http://localhost:8080/weather/services"/>
        </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>
    

    I am trying to setup a SoapUI test against these by pointing SoapUI to: http://localhost:8080/weather/services/temperature.wsdl

    Which generates a correct-looking (I think) SOAP request:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://nick.com/weather/schemas">
    <soapenv:Header/>
    <soapenv:Body>
       <sch:GetTemperaturesRequest>
          <sch:city>Chicago</sch:city>
          <!--1 to 5 repetitions:-->
          <sch:date>2014-06-24</sch:date>
       </sch:GetTemperaturesRequest>
    </soapenv:Body>
    </soapenv:Envelope>
    

    But sending the request through gives me a 404 response:

    HTTP/1.1 404 Not Found
    

    Any insights on what I might be doing wrong? THANKS!

  • evandongen
    evandongen almost 10 years
    Nice one, I didn't think to look at that (-: