camel-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Florent Legendre (Created) (JIRA)" <j...@apache.org>
Subject [jira] [Created] (CAMEL-5112) Erroneous support of Jaxb web services taking serveral Holder arguments
Date Fri, 23 Mar 2012 08:13:28 GMT
Erroneous support of Jaxb web services taking serveral 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


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 is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Mime
View raw message