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!
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!)
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