-<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://gumartinm.name/spring-ws/example" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://gumartinm.name/resource/wsdl/schemas" targetNamespace="http://gumartinm.name/resource/wsdl/schemas">
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://gumartinm.name/spring-ws/example" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://gumartinm.name/spring-ws/exampleService" targetNamespace="http://gumartinm.name/spring-ws/exampleService">
<wsdl:types>
<xs:schema xmlns:annox="http://annox.dev.java.net" xmlns:example="http://gumartinm.name/spring-ws/example" xmlns:inheritance="http://jaxb2-commons.dev.java.net/basic/inheritance" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:parent="http://gumartinm.name/spring-ws/parent" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" jaxb:extensionBindingPrefixes="inheritance annox" jaxb:version="2.1" targetNamespace="http://gumartinm.name/spring-ws/example">
<wsdl:part element="sch:CustomBindingExampleFault" name="CustomBindingExampleFault">
</wsdl:part>
</wsdl:message>
- <wsdl:message name="CustomBindingExampleRequest">
- <wsdl:part element="sch:CustomBindingExampleRequest" name="CustomBindingExampleRequest">
- </wsdl:part>
- </wsdl:message>
<wsdl:message name="ExampleRequest">
<wsdl:part element="sch:ExampleRequest" name="ExampleRequest">
</wsdl:part>
<wsdl:part element="sch:CustomBindingExampleResponse" name="CustomBindingExampleResponse">
</wsdl:part>
</wsdl:message>
+ <wsdl:message name="CustomBindingExampleRequest">
+ <wsdl:part element="sch:CustomBindingExampleRequest" name="CustomBindingExampleRequest">
+ </wsdl:part>
+ </wsdl:message>
<wsdl:portType name="Examples">
<wsdl:operation name="Example">
<wsdl:input message="tns:ExampleRequest" name="ExampleRequest">
</wsdl:binding>
<wsdl:service name="ExamplesService">
<wsdl:port binding="tns:ExamplesSoap12" name="ExamplesSoap12">
- <soap12:address location="http://localhost:8080/web-services-spring-jaxb2-server/spring-ws/example"/>
+ <soap12:address location="http://localhost:8080/web-services-spring-cxf-server/spring-ws/example"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
\ No newline at end of file
at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:888)
ESTE ERROR SE PRODUCE PORQUE cxf-codegen-plugin GENERA Examples QUE ES UN inteface @WebService
- maven-jaxb2-plugin NO GENERA ESTOS OBJETOS (otra razón más para usar maven-jaxb2-plugin)
+ maven-jaxb2-plugin NO GENERA ESTOS OBJETOS pero maven-jaxb2-plugin NO ES BUENO PARA GENERAR CLASES
+ DESDE WSDLs POR LAS RAZONES EXPLICADAS EN EL pom.xml DEL PROYECTO web-services-spring-jaxb2-client.
-->
<oxm:jaxb2-marshaller id="marshaller" context-path="de.spring.webservices.auto"/>
class="org.springframework.ws.client.support.interceptor.PayloadValidatingInterceptor">
<property name="schemas">
<list>
- <value>classpath:examples.xsd</value>
- <value>classpath:parent.xsd</value>
+ <!--
+ ALWAYS FIRST THE XSD FILES TO BE IMPORTED!!!!! O.o
+ OTHERWISE THE import IN examples.xsd WILL BE SOLVED BY MEANS OF DOWNLOADING THE
+ EXTERNAL parent.xsd (USING THE URL LINKED BY THE IMPORT STATEMENT IN examples.xsd)
+
+ IF YOU DON'T DO THIS, PayloadValidatingInterceptor WILL TRY TO CONNECT TO THE
+ EXTERNAL SERVER WHERE parent.xsd IS LOCATED AND IT WILL FAIL IF BECAUSE SOME
+ REASON YOU DON'T HAVE IN THAT VERY MOMENT NETWORK CONNECTION. SO, DON'T MESS WITH THIS
+ CONFIGURATION.
+ -->
+ <value>classpath:parent.xsd</value>
+
+ <value>classpath:examples.xsd</value>
</list>
</property>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
+
+ <!--
+ Strategies used by default (see WebServiceTemplate.properties file)
+
+ org.springframework.ws.client.core.FaultMessageResolver=org.springframework.ws.soap.client.core.SoapFaultMessageResolver
+ org.springframework.ws.WebServiceMessageFactory=org.springframework.ws.soap.saaj.SaajSoapMessageFactory
+ org.springframework.ws.transport.WebServiceMessageSender=org.springframework.ws.transport.http.HttpUrlConnectionMessageSender
+
+ -->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory"/>
+++ /dev/null
-package de.spring.webservices.endpoints;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
-import javax.xml.transform.Result;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.oxm.Marshaller;
-import org.springframework.util.CollectionUtils;
-import org.springframework.ws.soap.SoapFault;
-import org.springframework.ws.soap.SoapFaultDetail;
-import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
-import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
-import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
-
-import de.spring.webservices.auto.Element;
-import de.spring.webservices.auto.ExampleFault;
-import de.spring.webservices.exceptions.CustomBusinessException;
-
-public class MyCustomExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
- private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomExceptionResolver.class);
-
- private Marshaller marshaller;
-
- private Map<String, String> exceptionMappings = new LinkedHashMap<>();
-
- /**
- * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
- * no wildcard support at present.
- *
- * <p>The values of the given properties object should use the format described in
- * {@code SoapFaultDefinitionEditor}.
- *
- * <p>Follows the same matching algorithm as {@code SimpleMappingExceptionResolver}.
- *
- * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
- * values
- * @see SoapFaultDefinitionEditor
- */
- public void setExceptionMappings(Properties mappings) {
- for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
- if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
- exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
- }
- }
- }
-
- @Override
- protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
- if (!CollectionUtils.isEmpty(exceptionMappings)) {
- String definitionText = null;
- int deepest = Integer.MAX_VALUE;
- for (String exceptionMapping : exceptionMappings.keySet()) {
- int depth = getDepth(exceptionMapping, ex);
- if (depth >= 0 && depth < deepest) {
- deepest = depth;
- definitionText = exceptionMappings.get(exceptionMapping);
- }
- }
- if (definitionText != null) {
- SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
- editor.setAsText(definitionText);
- return (SoapFaultDefinition) editor.getValue();
- }
- }
- return null;
- }
-
- /**
- * Return the depth to the superclass matching. {@code 0} means ex matches exactly. Returns {@code -1} if
- * there's no match. Otherwise, returns depth. Lowest depth wins.
- *
- * <p>Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
- */
- protected int getDepth(String exceptionMapping, Exception ex) {
- return getDepth(exceptionMapping, ex.getClass(), 0);
- }
-
- @SuppressWarnings("unchecked")
- private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
- if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
- return depth;
- }
- if (exceptionClass.equals(Throwable.class)) {
- return -1;
- }
- return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
- }
-
- protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
- SoapFaultDetail detail = fault.addFaultDetail();
- Result result = detail.getResult();
-
- Element element = new Element();
- element.setMessage(ex.getMessage());
-
- if (ex instanceof CustomBusinessException) {
- List<String> arguments = element.getMessageArgs();
- arguments.add("ARGUMENT 1");
- arguments.add("ARGUMENT 2");
- }
-
- ExampleFault customFault = new ExampleFault();
- customFault.setTechnicalError(getStackTrace(ex));
- List<Element> elements = customFault.getElements();
- elements.add(element);
-
- try {
- marshaller.marshal(customFault, result);
- } catch (Exception marshallEx) {
- LOGGER.error("", marshallEx);
- }
- }
-
- public void setMarshaller(Marshaller marshaller) {
- this.marshaller = marshaller;
- }
-
- private static String getStackTrace(final Throwable throwable) {
- final StringWriter sw = new StringWriter();
- final PrintWriter pw = new PrintWriter(sw, true);
- throwable.printStackTrace(pw);
- return sw.getBuffer().toString();
- }
-}
--- /dev/null
+package de.spring.webservices.endpoints;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.xml.transform.Result;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.oxm.Marshaller;
+import org.springframework.util.CollectionUtils;
+import org.springframework.ws.soap.SoapFault;
+import org.springframework.ws.soap.SoapFaultDetail;
+import org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver;
+import org.springframework.ws.soap.server.endpoint.SoapFaultDefinition;
+import org.springframework.ws.soap.server.endpoint.SoapFaultDefinitionEditor;
+
+import de.spring.webservices.auto.Element;
+import de.spring.webservices.auto.ExampleFault;
+import de.spring.webservices.exceptions.CustomBusinessException;
+
+public class MyCustomMappingExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
+ private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomMappingExceptionResolver.class);
+
+ private Marshaller marshaller;
+
+ private Map<String, String> exceptionMappings = new LinkedHashMap<>();
+
+ /**
+ * Set the mappings between exception class names and SOAP Faults. The exception class name can be a substring, with
+ * no wildcard support at present.
+ *
+ * <p>The values of the given properties object should use the format described in
+ * {@code SoapFaultDefinitionEditor}.
+ *
+ * <p>Follows the same matching algorithm as {@code SimpleMappingExceptionResolver}.
+ *
+ * @param mappings exception patterns (can also be fully qualified class names) as keys, fault definition texts as
+ * values
+ * @see SoapFaultDefinitionEditor
+ */
+ public void setExceptionMappings(Properties mappings) {
+ for (Map.Entry<Object, Object> entry : mappings.entrySet()) {
+ if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
+ exceptionMappings.put((String)entry.getKey(), (String)entry.getValue());
+ }
+ }
+ }
+
+ @Override
+ protected SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
+ if (!CollectionUtils.isEmpty(exceptionMappings)) {
+ String definitionText = null;
+ int deepest = Integer.MAX_VALUE;
+ for (String exceptionMapping : exceptionMappings.keySet()) {
+ int depth = getDepth(exceptionMapping, ex);
+ if (depth >= 0 && depth < deepest) {
+ deepest = depth;
+ definitionText = exceptionMappings.get(exceptionMapping);
+ }
+ }
+ if (definitionText != null) {
+ SoapFaultDefinitionEditor editor = new SoapFaultDefinitionEditor();
+ editor.setAsText(definitionText);
+ return (SoapFaultDefinition) editor.getValue();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return the depth to the superclass matching. {@code 0} means ex matches exactly. Returns {@code -1} if
+ * there's no match. Otherwise, returns depth. Lowest depth wins.
+ *
+ * <p>Follows the same algorithm as RollbackRuleAttribute, and SimpleMappingExceptionResolver
+ */
+ protected int getDepth(String exceptionMapping, Exception ex) {
+ return getDepth(exceptionMapping, ex.getClass(), 0);
+ }
+
+ @SuppressWarnings("unchecked")
+ private int getDepth(String exceptionMapping, Class<? extends Exception> exceptionClass, int depth) {
+ if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
+ return depth;
+ }
+ if (exceptionClass.equals(Throwable.class)) {
+ return -1;
+ }
+ return getDepth(exceptionMapping, (Class<? extends Exception>) exceptionClass.getSuperclass(), depth + 1);
+ }
+
+ protected void customizeFault(Object endpoint, Exception ex, SoapFault fault) {
+ ExampleFault customFault = new ExampleFault();
+ customFault.setTechnicalError(getStackTrace(ex));
+
+ Element element = buildElement(ex);
+ List<Element> elements = customFault.getElements();
+ elements.add(element);
+
+ SoapFaultDetail detail = fault.addFaultDetail();
+ Result result = detail.getResult();
+ try {
+ marshaller.marshal(customFault, result);
+ } catch (Exception marshallEx) {
+ LOGGER.error("MyCustomMappingExceptionResolver: marshaller error", marshallEx);
+ }
+ }
+
+ public void setMarshaller(Marshaller marshaller) {
+ this.marshaller = marshaller;
+ }
+
+ private Element buildElement(Exception ex) {
+ Element element = new Element();
+ element.setMessage(ex.getMessage());
+
+ if (ex instanceof CustomBusinessException) {
+ CustomBusinessException customEx = (CustomBusinessException) ex;
+ List<String> messageArgs = element.getMessageArgs();
+ List<String> argumentsEx = customEx.getArguments();
+
+ for (String argumentEx: argumentsEx) {
+ messageArgs.add(argumentEx);
+ }
+ }
+
+ return element;
+ }
+
+ private String getStackTrace(Throwable throwable) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw, true);
+ throwable.printStackTrace(pw);
+ return sw.getBuffer().toString();
+ }
+}
import java.util.List;
/**
- * This exception will be caught by de.spring.webservices.endpoints.MyCustomExceptionResolver
+ * This exception will be caught by de.spring.webservices.endpoints.MyCustomMappingExceptionResolver
*
*/
public class CustomBusinessException extends RuntimeException {
// see soap-ws.xml Spring configuration file.
// throw new BusinessException("This feature has not been implemented yet.");
- // Example about how works de.spring.webservices.endpoints.MyCustomExceptionResolver
+ // Example about how works de.spring.webservices.endpoints.MyCustomMappingExceptionResolver
// see soap-ws.xml Spring configuration file.
// List<String> arguments = new ArrayList<>();
// arguments.add("ARGUMENT 1");
<sws:dynamic-wsdl id="example" portTypeName="Examples"
createSoap12Binding="true" createSoap11Binding="false"
locationUri="/spring-ws/example"
- targetNamespace="http://gumartinm.name/resource/wsdl/schemas">
+ targetNamespace="http://gumartinm.name/spring-ws/exampleService">
<sws:xsd location="classpath:examples.xsd"/>
</sws:dynamic-wsdl>
- <bean id="parent" class="org.springframework.xml.xsd.SimpleXsdSchema">
- <property name="xsd" value="classpath:parent.xsd"/>
- </bean>
-
-
<!-- Required in order to use SOAP 1.2
id="messageFactory" is not a random choice, if you use another name it will not work
(Spring will end up loading SOAP 1.1)
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schemas">
<list>
- <value>classpath:examples.xsd</value>
+ <!--
+ ALWAYS FIRST THE XSD FILES TO BE IMPORTED!!!!! O.o
+ OTHERWISE THE import IN examples.xsd WILL BE SOLVED BY MEANS OF DOWNLOADING THE
+ EXTERNAL parent.xsd (USING THE URL LINKED BY THE IMPORT STATEMENT IN examples.xsd)
+
+ IF YOU DON'T DO THIS, PayloadValidatingInterceptor WILL TRY TO CONNECT TO THE
+ EXTERNAL SERVER WHERE parent.xsd IS LOCATED AND IT WILL FAIL IF BECAUSE SOME
+ REASON YOU DON'T HAVE IN THAT VERY MOMENT NETWORK CONNECTION. SO, DON'T MESS WITH THIS
+ CONFIGURATION.
+ -->
<value>classpath:parent.xsd</value>
+
+ <value>classpath:examples.xsd</value>
</list>
</property>
<property name="validateRequest" value="true"/>
class="org.springframework.ws.soap.server.endpoint.SoapFaultMappingExceptionResolver">
<!--
No quiero usar un valor por defecto porque si no, si mi manejador no machea ninguna excepción
- devolvera este valor por defecto.
+ devolvera este valor por defecto. Y no se probará con otros manejadores de excepción que tengan un order con menor precedencia.
Cuando se escribe value="SERVER" Spring está seteando SoapFaultDefinition.SERVER en defaultValue
de org.springframework.ws.soap.server.endpoint.AbstractSoapFaultDefinitionExceptionResolver Esto parece
- <bean id="myCustomExceptionResolver" class="de.spring.webservices.endpoints.MyCustomExceptionResolver">
+ <bean id="myCustomMappingExceptionResolver" class="de.spring.webservices.endpoints.MyCustomMappingExceptionResolver">
+ <!--
+ Voy a usar un valor por defecto porque este va a ser el último manejador que haya antes de
+ SimpleSoapExceptionResolver. SimpleSoapExceptionResolver será siempre por el order que he puesto
+ el último manejador de excepciones.
+ Así todas las excepciones que no hayan sido macheadas por los otros manejadores serán siempre
+ cogidas por este y se les asignará un SoapFaultDefinition.SERVER. En este caso SimpleSoapExceptionResolver
+ nunca será usado.
+ -->
+ <property name="defaultFault" value="SERVER"/>
<property name="exceptionMappings">
<props>
-
<prop key="de.spring.webservices.exceptions.CustomBusinessException">SERVER</prop>
</props>
</property>