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


Reply via email to