Custom JAXB Binding Causes Namespace Error

821 Views Asked by At

History

I am generating Java classes from a schema not under my control. I am exporting it to a jar that is a dependency for a web service project. This works correctly. I attempted to add a custom binding to marshal and unmarshal xs:date and xs:dateTime as instances of org.joda.DateTime instead of XMLGregorianCalendar. I am able to generate the jar, compile it within the webservice, and deploy without issue. Once deployed however, the XML requests that previously worked, now throw the following exception:

unexpected element (uri:"", local:"ElementName"). Expected elements are <{schemaNamespace}ElementName>

This exception does not occur at the root element. Several earlier instances of xs:date and xs:dateTime are parsed without issue, the exception first appears on a complex type that contains an xs:date.

Here's an example of the XML structure:

<soap:Envelope xmlns:ns="webServiceNamespace">
    <soap:Body>
        <request>
           <root>
                  <child1>
                       <Date /> <--Works fine.
                       <childList>
                             <childListElement> <-- Exception thrown on this element.
                                  <Date />
                             </childListElement>
                        </childList>
                  </child1>
             </root>
       </request>
    </soap:Body>
</soap:Envelope>

The webServiceNamespace and schemaNamespace are different, but previously only the one was required in the soap envelope.

Question

Why, after adding a custom binding, is the parser asking me to put a namespace on only a handful of parent elements who have a child affected by the custom binding ?

BindingAdapter

 package myPackage;

 @XmlTransient
 public class JodaDateTimeAdapter extends XmlAdapter<String, DateTime> {

    private static final DateTimeFormatter XML_DATE_FORMAT = ISODateTimeFormat.dateTimeNoMillis();

    @Override
    public DateTime unmarshal(String date) throws Exception {
        return XML_DATE_FORMAT.parseDateTime(date);
    }

    @Override
    public String marshal(DateTime dateTime) throws Exception {
        return XML_DATE_FORMAT.print(dateTime);
    }
 }

Binding.xjb

 <?xml version="1.0" encoding="UTF-8"?>
 <jaxb:bindings     xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" 
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb           http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd"
                jaxb:extensionBindingPrefixes="xjc"
                version="2.1" >
     <jaxb:globalBindings>
         <xjc:javaType name="org.joda.time.DateTime" xmlType="xs:dateTime" adapter="myPackage.JodaDateTimeAdapter" />
         <xjc:javaType name="org.joda.time.DateTime" xmlType="xs:date" adapter="myPackage.JodaDateAdapter" />
     </jaxb:globalBindings>
 </jaxb:bindings>

POM.xml(relevant bits anyway)

 <project>
     ...
     <build>
         <pluginManagement>
             <plugins>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
                     <configuration>
                         <source>1.7</source>
                         <target>1.7</target>
                     </configuration>
                 </plugin>
             </plugins>
         </pluginManagement>
         <plugins>
             ...
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>jaxb2-maven-plugin</artifactId>
                 <version>1.6</version>
                 <executions>
                     ...
                         <execution>
                         <id>generateSchema</id>
                         <goals>
                             <goal>xjc</goal>
                         </goals>
                         <configuration>
                             <packageName>myPackage</packageName>
                             ...
                             <extension>true</extension>
                             <arguments>-no-header -Xxew</arguments>
                             <bindingDirectory>src/main/bindings</bindingDirectory>
                             <bindingFiles>JodaBinding.xjb</bindingFiles>
                         </configuration>     
                     </execution>           
                 </executions>
                 <dependencies>
                <dependency>
                        <groupId>com.github.jaxb-xew-plugin</groupId>
                        <artifactId>jaxb-xew-plugin</artifactId>
                        <version>RELEASE</version>
                    </dependency>            
                 </dependencies>
             </plugin>
         </plugins>
     </build>
 </project>

Comments

I want to stress that this works perfectly fine without the binding, as far as I can tell the generated class files are identical (except for the extra annotations specific to wrappers). The xml used in the SOAP request is valid for the WSDL generated by the web service, and the WSDL is the same whether or not I use a custom binding. Only elements who have are a member of a collection and have a child with a date require the schema namespace. Lastly, once I provide the namespaces in my request, the response puts the request object in the webServiceNamespace and all the children other than the schema-defined root in the schemaNamespace. Previously the entire response was in the webServiceNamespace.

Clearly the addition of the custom binding is doing something wonky (technical term) with the namespace resolution, but I'm not well versed enough in the topic to make any headway.

Suggestions ?

Update: Removing the XEW plugin for pretty-collections generation did not affect this issue.

Update: This is an example of a class containing a date before the binding and after. This is the only property to change:

Before

 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "QuestionAnswerType", propOrder = {
     "question",
     "answer",
     "questionDate"
 })
 public class QuestionAnswerType {

     @XmlElement(name = "Question")
     protected String question;
     @XmlElement(name = "Answer")
     protected String answer;
     @XmlElement(name = "QuestionDate")
     @XmlSchemaType(name = "date")
     protected XMLGregorianCalendar questionDate;
      ...

After

 @XmlAccessorType(XmlAccessType.FIELD)
 @XmlType(name = "QuestionAnswerType", propOrder = {
     "question",
     "answer",
     "questionDate"
 })
 public class QuestionAnswerType {

     @XmlElement(name = "Question")
     protected String question;
     @XmlElement(name = "Answer")
     protected String answer;
     @XmlElement(name = "QuestionDate", type = String.class)
     @XmlJavaTypeAdapter(JodaDateAdapter.class)
     @XmlSchemaType(name = "date")
     protected DateTime questionDate;
      ...

Update: This works without issue if I execute the build against a schema with no namespace. Obviously not the fix, but a workaround for now.

0

There are 0 best solutions below