Actually, just to be a bit more specific ....
On 28.01.2010 21:02, Lukas Lang wrote:
Hello Paul,
unfortunately, Spring WS does not provide sophisticated configuration and
customization methods of the integrated Castor marshaller/unmarshaller, to be
more specific: a setter for the XMLContext. We have experienced this issue in a
professional environment several times and I recommend proceeding as follows
1. extend Spring's CastorMarshaller
2. hook your Castor configuration into the lifecycle
You can find a small example attached.
To deal with your second problem, I'd recommend generating all types using
Castor (e.g. the Castor Maven plugin[1]) from a separated XML schema (have a
look at the Spring WS documentation for automatically creating a WSDL in case
you aren't familiar). Don't forget to map XML namespaces to packages properly
as specified in [2] before code generation. Class descriptors should then be
aware of the proper namespaces.
Hope that helps.
Regards,
Lukas
PS: It would be awesome if you would provide us or the Spring team with a patch!
That problem has already been reported with the Spring (WS) guys, and a
patch has already been committed to SVN trunk (Spring 3.0). And yes,
this is a bit complicated ..... ;-).
Regards
Werner
[1] http://mojo.codehaus.org/castor-maven-plugin/
[2]
http://www.castor.org/srcgen-properties.html#Mapping-XML-namespaces-to-Java-packages
--------------
public class WsCastorMarshaller extends CastorMarshaller {
private String[] packages = {};
private Log log = LogFactory.getLog(WsCastorMarshaller.class);
@Override
protected void customizeMarshaller(Marshaller marshaller) {
XMLClassDescriptorResolver resolver = configureResolver();
marshaller.setResolver(resolver);
}
@Override
protected void customizeUnmarshaller(Unmarshaller unmarshaller) {
XMLClassDescriptorResolver resolver = configureResolver();
unmarshaller.setResolver(resolver);
}
private XMLClassDescriptorResolver configureResolver() {
XMLClassDescriptorResolver resolver = (XMLClassDescriptorResolver)
ClassDescriptorResolverFactory
.createClassDescriptorResolver(BindingType.XML);
Introspector introspector = new Introspector();
introspector.setInternalContext(marshaller.getInternalContext());
resolver.setIntrospector(introspector);
try {
resolver.addPackages(this.packages);
} catch (ResolverException e) {
log.error("Error while customizing Castor
marshaller/unmarshaller.", e);
}
return resolver;
}
public void setPackages(String[] packages) {
this.packages = packages;
}
}
--------------
Am 28.01.2010 um 20:11 schrieb Paul French:
Hello,
Okay made some progress for the below.
I’ve written a simple main method to test Castor in isolation and even though
it works there looks like a bug to me which obviously causes a problem when
passing a fragment of XML to Castor to unmarshall.
The test program is shown below.
What happens is when the<usernameWRONG> element is processed castor cannot find a
descriptor for it. However before the tag<usernameWRONG> castor has found the descriptor
for<LoginRequest> as you would expect. What I don’t expect is that when Castor fails to
find a descriptor for usernameWRONG it adds all the descriptors it found for the package where
the LoginRequest lives all over again. So you end up with the same descriptor twice for some
classes in the descriptor cache.
Hence on subsequent calls with a valid XML doc when
XMLClassDescriptorResolverImpl.resolveByXMLName(final String xmlName, final
String namespaceURI, finalClassLoader loader) is called it finds 2 possible
matches for a descriptor. In the standalone program it manages to resolve to
one of these since the namespace is set explicitly. When used from within
Spring Web Services it cannot resolve a descriptor from the 2 possible matches
since I assume the namespace is not set explicitly in the XML doc since the
namespace declaration is defined in SOAP header.
Any ideas how to progress this? Someone can bring the whole web service down by
simply sending a slightly incorrect SOAP request.
Thanks
Paul
public static void main(String[] args) throws Exception
{
XMLContext context = new XMLContext();
context.addPackages(new
String[]{"com.kirona.mitie.model.web.server.concept","com.kirona.mitie.model.web.server.concept.types"});
Unmarshaller unMarshaller = context.createUnmarshaller();
try
{
System.out.println("TEST 1 – this will fail due to incorrect XML tag
usernameWRONG");
LoginRequest loginRequest = (LoginRequest) unMarshaller.unmarshal(new
StringReader("<sch:LoginRequest
xmlns:sch=\"http://kirona.com/2009/12/Concept/schema/\">\n"+
"<sch:usernameWRONG>paul</sch:usernameWRONG>\n"+
"<sch:password>password</sch:password>\n"+
"</sch:LoginRequest>"));
System.out.println("TEST 1 OK");
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("\n\n*****************************************************************\n\n");
try
{
System.out.println("TEST 2");
LoginRequest loginRequest = (LoginRequest) unMarshaller.unmarshal(new
StringReader("<sch:LoginRequest
xmlns:sch=\"http://kirona.com/2009/12/Concept/schema/\">\n"+
"<sch:username>paul</sch:username>\n"+
"<sch:password>arsenal</sch:password>\n"+
"</sch:LoginRequest>"));
System.out.println("TEST 2 OK");
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("\n\n*****************************************************************\n\n");
}
From: Paul French [mailto:[email protected]]
Sent: 28 January 2010 13:11
To: '[email protected]'
Subject: Very Strange Problem
Hello, we use Spring-WS and castor 1.3.1 for unmarshalling and marshalling.
Spring-WS provides a class CastorMarshaller to handle the unmarshalling and
marshalling for you. We have had to override one method in this class since it
does not support adding descriptors to the XMLContext.
So we have a bunch of model objects (as well as the .castor.cdr files) and a
bunch of descriptors which are registered with the XMLContext using the
addPackage(packageDescriptor) method
When we make a call like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sch="http://kirona.com/2009/12/Concept/schema/">
<soapenv:Header/>
<soapenv:Body>
<sch:LoginRequest>
<sch:username>username</sch:username>
<sch:password>password</sch:password>
</sch:LoginRequest>
</soapenv:Body>
</soapenv:Envelope>
…the request is marshalled fine.
If we then make a mistake in the SOAP request e.g.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:sch="http://kirona.com/2009/12/Concept/schema/">
<soapenv:Header/>
<soapenv:Body>
<sch:LoginRequest>
<sch:usernameWRONG>xxxx</sch:usernameWRONG>
<sch:password>xxxxxx</sch:password>
</sch:LoginRequest>
</soapenv:Body>
</soapenv:Envelope>
…we get the error (in the SOAP fault respone)
“Castor unmarshalling exception: unable to find FieldDescriptor for
'usernameWRONG' in ClassDescriptor of LoginRequest; nested exception is
org.exolab.castor.xml.MarshalException: unable to find FieldDescriptor for
'usernameWRONG' in ClassDescriptor of LoginRequest”
…which makes sense. However if I repeat the incorrect SOAP request I get…………..
“Castor unmarshalling exception: The class for the root element 'LoginRequest'
could not be found.; nested exception is
org.exolab.castor.xml.MarshalException: The class for the root element
'LoginRequest' could not be found.”
….it seems to no longer know what the element LoginRequest is anymore??
If I correct the SOAP request it still does not work, I still get the previous
error.
I can get things to work again by re-structuring the SOAP request as follows
(by moving the namespace declaration):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<sch:LoginRequest xmlns:sch="http://kirona.com/2009/12/Concept/schema/">
<sch:username>username</sch:username>
<sch:password>password</sch:password>
</sch:LoginRequest>
</soapenv:Body>
</soapenv:Envelope>
…and from this point onwards this is the only way it will work.
I know this is a bit SOAP related but it is the marshalling layer that is
failing. Any ideas?
P
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:
http://xircles.codehaus.org/manage_email