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!

[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


Reply via email to