Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jaxb validation against schema with only complex types

I have a wsdl that contains request and response elements:

<xsd:element name="someRequest" type="ns:SomeRequest"/>

<xsd:element name="someResponse" type="ns:SomeResponse"/>

This wsdl imports a few xsd's, which contain, among others, these complexTypes:

<xsd:complexType name="SomeRequest">
    ...
</xsd:complexType>

<xsd:complexType name="SomeResponse">
    ...
</xsd:complexType>

I want to validate an xml against this wsdl, but I can't get it to work. I'm basically using the method described on http://actimem.com/java/jaxb-validation/#Marshalling_Validation, by marshalling the object and setting a Schema and EventHandler.

If I set the Schema to the xsd, it won't validate because there's no element in the xsd. This is pretty logical, I get the same with other tools. When I use the wsdl as Schema, I get this error because of inline documentation:

s4s-elt-character: Non-whitespace characters are not allowed in schema elements other than 'xs:appinfo' and 'xs:documentation'.

Is there any way to get this to validate?

Since I'm working on existing projects (currently using Xmlbeans instead of JAXB) with a set workflow, I have to work with a few constraints:

  • These schemas were not made by us and can't be edited, so removing the docs or adding the elements isn't an option.
  • I would prefer to load the xsd's from 1 place because of duplication and possible human errors. Xsd's are stored in a separate project, which builds jars we include as dependencies in our projects. The jars that contain the xjc generated classes also contain the schemas.
  • The xsd's contain a lot of imports.
  • Because of namespacing and classloading collisions, I can't use the ObjectFactory generated by xjc. Multiple xsd's have the same namespace but are actually different, and this has caused issues with the wrong ObjectFactory getting loaded in generic projects that use multiple xsd's.

I've tried transforming the schema to add the element manually, but I can't find a way to do it on an existing Schema object. If I do this through DOM manipulation, I get the new schema as a String object, which won't parse into a Schema because the imported xsd's can't be found.

If I copy the xsd's from the jar to the project, I can transform them and get the validation to succeed, but I don't really like this solution. If there's no other way, I'll revert to that, but I would like to find a solution that requires as little work as possible when reusing this method and is the least prone to errors. Other developers will use this code and 1 validate method without needing extra steps to work would be perfect.

I ran into basically this problem before and didn't find a solution then, either. But before, the complexType wasn't the root element and I could just wrap it into other objects until I found an object that was represented as element in the xsd.

like image 921
Ivo van der Veeken Avatar asked Mar 08 '17 14:03

Ivo van der Veeken


1 Answers

You may consider to look at javax.xml.validation.Validator class. There is a way to create it for schema in the WSDL document and then you will have your someRequest element you can validate against that schema.

code may look like:

import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import org.xml.sax.ErrorHandler;

...
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
String testXml = "{your XML document}"
Document domDoc = docBuilder.parse(new ByteArrayInputStream(testXml.getBytes()));
Source inputSource = new DOMSource(domDoc);
Validator validator = requestedSchema.newValidator();
MySchemaValidationErrorHandler errHandler = new MySchemaValidationErrorHandler();

SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema requestedSchema = schemaFactory.newSchema({DOMSource from WSDL document/types/xsd:schema node}));
validator.setErrorHandler(errHandler);
validator.validate(inputSource);

Note that you need to have your own implementation of org.xml.sax.ErrorHandler interface where all warnings and errors will be collected during validation.

In general it is not hard to make all of that. You just need

  1. have Schema Source from WSDL needed definitions/types/xsd:schema Node. it is doable through DOMSource
  2. Pass it as Schema parameter when creates Schema object from schemaFactory.newSchema(...) method
  3. Implement org.xml.sax.ErrorHandler interface where all errors be collected. It is very simple
  4. Handle those errors either right out of handler or collect them and deal with them after validator completes its work. It is up to you...

PS. Usually I create needed Schemas once and keep them in the Map. Just keep in mind - Validator is not thread safe.

of course you can use any other javax.xml.transform.Source implementations, not only DOMSource

like image 148
Vadim Avatar answered Sep 30 '22 09:09

Vadim