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