Problem with JAXB and @RequestBody
I'm using a controller that accepts POST requests with XML payload and uses JAXB with schema validation enabled to unmarshal. I use several schemata, my marshaller configuration is:
Code:
<beans:bean id="xmlMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<beans:property name="contextPath" value="demo.og.com.model"/>
<beans:property name="schemas">
<beans:list>
<beans:value>classpath:schemas/common-0.1.xsd</beans:value>
<beans:value>classpath:schemas/payment-0.1.xsd</beans:value>
<beans:value>classpath:schemas/contract-0.1.xsd</beans:value>
</beans:list>
</beans:property>
</beans:bean>
A demo controller is:
Code:
@RequestMapping(value="/cost", method=RequestMethod.POST )
public String echoCost( @RequestBody CostItem ci, Model model ) {
logger.debug( "Cost: " + ci.getCost().getCostTotal() );
model.addAttribute( ci );
return "costView";
}
In this case, CostItem is a class generated by xjc and it corresponds to an the costItem element described in common-1.0.xsd:
Code:
<xs:complexType name="cost">
<xs:sequence>
<xs:element name="costBeforeVat" type="xs:float" />
<xs:element name="vatPercentage" type="xs:int" />
<xs:element name="costTotal" type="xs:float" />
<xs:element name="currency" type="xs:string" />
</xs:sequence>
</xs:complexType>
<xs:element name="costItem">
<xs:complexType>
<xs:sequence>
<xs:element name="cost" type="tns:cost"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Then I use a similar method to handle an ArrayOfContracts object, which is described in contract-0.1.xsd (bear with me):
Code:
<xs:complexType name="contractItem">
<xs:sequence>
<xs:element name="since" type="xs:date" />
<xs:element name="until" type="xs:date" />
<xs:element name="cost" type="common:cost" />
<xs:element name="cpvCodes" type="tns:arrayOfCpvCodes"
minOccurs="0" />
<xs:element name="description" type="xs:string" />
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="optional" />
</xs:complexType>
<xs:complexType name="arrayOfContractItems">
<xs:sequence>
<xs:element name="item" type="tns:contractItem"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="contract">
<xs:sequence>
<xs:element name="contractNumber" type="xs:string" />
<xs:element name="primaryParties" type="tns:arrayOfContractParties" />
<xs:element name="secondaryParties" type="tns:arrayOfContractParties" />
<xs:element name="contractItems" type="tns:arrayOfContractItems" />
<xs:element name="contractDate" type="xs:date" />
<xs:element name="complementsContract" type="xs:string" minOccurs="0" />
<xs:element name="replacesContract" type="xs:string" minOccurs="0" />
<xs:element name="isDeleted" type="xs:boolean" default="false" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="id" type="xs:string" use="optional" />
</xs:complexType>
<xs:element name="arrayOfContracts">
<xs:complexType>
<xs:sequence>
<xs:element name="contract" type="tns:contract"
minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
Notice that cost in each ContractItem references the common-1.0 namespace.
Everything works fine, until i try to post an invalid document, i.e. one without a contractDate. As expected, I get an exception:
Code:
DEBUG: org.springframework.web.servlet.DispatcherServlet - Could not complete request
org.springframework.oxm.MarshallingFailureException: JAXB marshalling exception; nested exception is javax.xml.bind.MarshalException
- with linked exception:
[org.xml.sax.SAXParseException: cvc-complex-type.2.4.b: The content of element 'contract' is not complete. One of '{"http://demo.og.com/schema/contract-0.1":contractDate}' is expected.]
After this point, whenever I send a valid document, I keep getting the same MarshalException exception, the framework seems to ignore the new payload. Redeploying the app fixes the issue. I don't have this problem when I unmarshal the simpler CostItem element, sending an invalid request throws the exception just for that request, not for every subsequent one.
Any suggestions?