You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@camel.apache.org by "Florent Legendre (Updated) (JIRA)" <ji...@apache.org> on 2012/03/23 09:15:26 UTC

[jira] [Updated] (CAMEL-5112) Erroneous support of Jaxb web services taking serveral Holder arguments

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

Florent Legendre updated CAMEL-5112:
------------------------------------

    Description: 
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}

  was:
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}}

    
> 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