Jeff Morin
Jeff Morin

Reputation: 1010

JAX-WS RI does not enforce XSD restrictions

I am currently developing a few Web services using the JAX-WS reference implementation (version 2.1.7). They are contract-based, that is, the WSDL and XSD files are not generated by wsgen.

This allows me to freely use XSD restrictions to strengthen validation of values passed to my services through SOAP messages. Here are two examples of such "restricted" XSD elements:

<xsd:element name="maxResults" minOccurs="1">
  <xsd:simpleType>
    <xsd:restriction base="xsd:positiveInteger">
      <xsd:minInclusive value="1"/>
      <xsd:maxInclusive value="1000"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>
<xsd:element name="lastName" minOccurs="0">
  <xsd:simpleType>
    <xsd:restriction base="xsd:string">
      <xsd:minLength value="1"/>
      <xsd:maxLength value="25"/>
    </xsd:restriction>
  </xsd:simpleType>
</xsd:element>

I added the @SchemaValidation annotation to my service classes to enforce schema validation. However, JAX-WS does not enforce validation rules as expected. The behaviour is as follows:

In other words, restrictions that appear in <xsd:element> tags are correctly enforced but <xsd:restriction> elements seem to be totally ignored by JAXB when used in a JAX-WS-based context.

I wrote a test class to check my XSD restrictions using bare JAXB (no JAX-WS). As a result, all restrictions are correctly enforced.

This gives me the feeling that there might be a bug in the usage of JAXB by JAX-WS... unless there is something I am doing incorrectly, of course...

Am I missing something fundamental here?!?

Thanks in advance for any help,

Jeff

Upvotes: 5

Views: 8267

Answers (2)

Jeff Morin
Jeff Morin

Reputation: 1010

Oh brother!...

In order to override the wsdlLocation for my JUnit tests, I created derivations of my Web service implementations that override only the @WebService annotation. As a result, I ran into the same problem I finally solved this morning (ref. my first answer above).

After doing plenty of tests, I figured out that it's the presence of a @WebService-annotated class extending my Web service implementation that prevents XSD validation from properly handling <xsd:restriction> tags.

To illustrate this bizarre behaviour, let's suppose I have the following classes:

@WebService(...)
public interface JeffWebService {...}

@WebService(..., wsdlLocation = "path/myWsdl.wsdl", ...)
public class JeffWebServiceImpl implements JeffWebService {...}

where path/myWsdl.wsdl correctly locates the WSDL. Then XSD validation works properly, i.e. the content of my first answer above is totally valid.

I now add the following class that I use in my JUnit-based Endpoint.publish() calls:

@WebService(..., wsdlLocation = "alternatePath/myWsdl.wsdl", ...)
public class TestWebServiceImpl extends JeffWebServiceImpl {}

that overrides nothing but the @WebService annotation. Then XSD validation excludes <xsd:restriction> tags as it used to do before specifying the wsdlLocation attribute at all, despite the fact that I still use the JeffWebServiceImpl implementation in my non-JUnit code! If I comment out the annotation in TestWebServiceImpl, then everything works properly again, except for unit tests, of course.

In other words, as soon as there is some class extending my Web service implementation in the classpath, the @WebService annotation of the most specific class overrides all others, regardless of the actual class I use in a regular Web application context. Weird, isn't it?!?

Bottom line: I will disable Endpoint-based unit tests for now. If I (or anyone reading this thread) find a clean, non-bogus way to integrate both production and JUnit configurations, I will consider putting them back in my JUnit test suite.

I hope this thread will help anyone running into the same problem solve it faster than I did...

Jeff

Upvotes: 1

Jeff Morin
Jeff Morin

Reputation: 1010

I finally found what's wrong...

In order to get my Web services to work in a JUnit context, i.e. published through Endpoint.publish(), I had to remove the wsdlLocation attribute from my @WebService annotations. If I don't, the wsdlLocation = "WEB-INF/wsdl/SearchIndividualsV1_0.wsdl" passed to the @WebService annotation clashes with the URL value passed to the Endpoint.publish() method, http://127.0.0.1:9000/rpe-ws/SearchIndividuals.

After reading Glen Mazza's Weblog (http://www.jroller.com/gmazza/entry/soap_xml_schema_validation), Additional Notes section, I put back the wsdlLocation attribute and all restrictions are now properly enforced.

In other words, removing the wsdlLocation in a @WebService annotation does not prevent the service itself from working, but prevents restrictions declared in <xsd:restrictions> elements from being properly enforced. Restrictions declared in <xsd:element> elements, however, are still correctly enforced.

I am therefore getting back to having to solve that wsdlLocation compatibility problem to make my unit tests work properly, but this is way less critical than non-working validations in a production context...

Just in case... Anyone has an idea about this WSDL location incompatibility when running a Web service in a non-Web context?

Thanks,

Jeff

Upvotes: 3

Related Questions