You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Claus Ibsen (JIRA)" <ji...@apache.org> on 2016/05/06 11:30:13 UTC

[jira] [Resolved] (CAMEL-5112) camel-soap - Erroneous support of Jaxb web services taking several Holder arguments

     [ https://issues.apache.org/jira/browse/CAMEL-5112?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Claus Ibsen resolved CAMEL-5112.
--------------------------------
    Resolution: Unresolved
      Assignee: Claus Ibsen

> camel-soap - Erroneous support of Jaxb web services taking several Holder arguments 
> ------------------------------------------------------------------------------------
>
>                 Key: CAMEL-5112
>                 URL: https://issues.apache.org/jira/browse/CAMEL-5112
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-soap
>    Affects Versions: 2.9.0
>         Environment: $> java -version
> java version "1.6.0_29"
> Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-11D50d)
> Java HotSpot(TM) 64-Bit Server VM (build 20.4-b02-402, mixed mode)
> $> uname -a
> 11.3.0 Darwin Kernel Version 11.3.0: Thu Jan 12 18:47:41 PST 2012; root:xnu-1699.24.23~1/RELEASE_X86_64 x86_64
>            Reporter: Florent Legendre
>            Assignee: Claus Ibsen
>            Priority: Minor
>             Fix For: Future
>
>
> Hi,
> *NB*
> I ran into a problem while using the camel-soap module. I have created a patched version of the problematic classes and am totally open for submitting them for review in hope that it could increase the chance for this bug to be fixed in a near future. 
> *The problem*
> I have to integrate with a web service with that type of signature (generated from the original wsdl file with the help of wsimport):
> {code}
> @WebMethod
> @WebResult(name = "Details", targetNamespace = "http://example.com/service.xsd", partName = "response")
> public Details fetchDetails(
>         @WebParam(name = "fetchDetails", targetNamespace = "http://example.com/service.xsd", partName = "fetchDetails")
>         Personsearch fetchDetails,
>         @WebParam(name = "Session", targetNamespace = "http://example.com/service.xsd", header = true, mode = WebParam.Mode.INOUT, partName = "Session")
>         Holder<Session> session,
>         @WebParam(name = "Transaction", targetNamespace = "http://example.com/service.xsd", header = true, partName = "Transaction")
>         Transaction transaction,
>         @WebParam(name = "Transactioninfo", targetNamespace = "http://example.com/service.xsd", header = true, mode = WebParam.Mode.OUT, partName = "Transactioninfo")
>         Holder<Transactioninfo> transactionInfo)
>         throws FetchDetailsException
>     ;
> }}
> {code}
> The call to the web service is set up as documented in the wiki (all this done in the context of a {{Processor#process(Exchange)}} method)
> * Create a bean invocation
> * Set the Method object representing the method to be called (fetchDetails in my case) on the bean invocation
> * build the parameters for the method call and set them on the bean invocation.
> * Set the bean invocation in the out body of the exchange
> This kind of setup leads to incorrect generation of the xml sent to the webservice. The reason for this is:
> * When specifying the method to invoke i have to write {{beanInvocation.setMethod(ServicePortType.class.getMethod(WS_METHOD_NAME, Personsearch.class, Holder.class, Transaction.class, Holder.class));}}. Note that this method signature contains two Holder objects.
> * When {{ServiceInterfaceStrategy}} goes through {{#analyzeServiceInterface}} it uses the name of the class object passed in the signature as key in the {{ServiceInterfaceStrategy.inTypeNameToQName}} Map. 
> * Because there are two {{Holder}} instances in the signature it means that only one of the two QName which are added to the map will be found, as they both rely on the same {{Holder.class}}-based key
> * The problem above occurs when {{ServiceInterfaceStrategy#findQNameForSoapActionOrObject}} reads from {{ServiceInterfaceStrategy.inTypeNameToQName}}, getting the exact same QName out of the map for both objects, hence generating erroneous xml (Note that nothing fails, it just sends rubbish to the webservice)
> *A solution*
> Files that I "Patched" to get this case to work:
> * org.apache.camel.dataformat.soap.name.ElementNameStrategy
> * org.apache.camel.dataformat.soap.name.ServiceInterfaceStrategy
> * org.apache.camel.dataformat.soap.name.TypeNameStrategy
> * org.apache.camel.dataformat.soap.SoapJaxbDataFormat
> My solution relies on the following:
> * For the end user the "receipe" is still exactly the same with use of BeanInvocation
> * I have created a utility class to generate suitable keys for adding/retrieving Holder objects (see further down).
> * I modified the method {{PatchedElementNameStrategy#findQNameForSoapActionOrObject(String soapAction, Object object)}} to take an object parameter instead of a class. This gives this method the correct tool (the object, not the class) to produce a key which actually retrieves the correct QName
> All this works fine for me and I would like to submit my patch to the project.
> {code}
> package org.apache.camel.dataformat.soap.name;
> import javax.xml.ws.Holder;
> import java.lang.reflect.ParameterizedType;
> import java.lang.reflect.Type;
> public final class ElementNameStrategyUtils {
>     private ElementNameStrategyUtils() {
>         // utility class
>     }
>     /**
>      * Generates a suitable key for adding a QName in one of the <code>Map<String, QName></code> <code>PatchedServiceInterfaceStrategy</code>.
>      *
>      * @param type
>      * @return
>      */
>     public static String getTypeNameForType(Type type) {
>         if (type instanceof ParameterizedType) {
>             ParameterizedType parameterizedType = (ParameterizedType) type;
>             StringBuffer typeName = new StringBuffer();
>             Class<?> rawTypeAsClass = (Class<?>) parameterizedType.getRawType();
>             typeName.append(rawTypeAsClass.getName());
>             for (int i = 0; i < parameterizedType.getActualTypeArguments().length; i++) {
>                 Type actualTypeArg = parameterizedType.getActualTypeArguments()[i];
>                 typeName.append("-");
>                 typeName.append(getTypeNameForType(actualTypeArg));
>             }
>             return typeName.toString();
>         } else {
>             Class<?> typeAsClass = (Class<?>) type;
>             return typeAsClass.getName();
>         }
>     }
>     /**
>      * Generates a suitable key for retrieving a QName from one of the <code>Map<String, QName></code> <code>PatchedServiceInterfaceStrategy</code>.
>      *
>      * @param object
>      * @return
>      */
>     public static String getTypeNameForObject(Object object) {
>         if (object instanceof Holder) {
>             Holder holder = (Holder) object;
>             StringBuffer typeName = new StringBuffer();
>             typeName.append(holder.getClass().getName());
>             if (holder.value != null) {
>                 typeName.append("-");
>                 typeName.append(getTypeNameForObject(holder.value));
>             }
>             return typeName.toString();
>         } else {
>             return object.getClass().getName();
>         }
>     }
> }
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)