We have a JAX-WS/JAXB binding to an external web-service that is working fine on Java 7 (1.7.0u80) with the included reference implementations. During migration to Java 8 (1.8.0u66) the web service calls generally work OK, however it cannot unmarshall SOAP faults and their detail elements to Java Exceptions with custom detail any longer, giving instead a prefix not bound to a namespace error.
The failure is
Caused by: javax.xml.ws.WebServiceException: java.lang.IllegalArgumentException: prefix xsd is not bound to a namespace
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:138)
at com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238)
at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:189)
at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:276)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:104)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147)
at com.sun.proxy.$Proxy61.proprietaryServiceCall(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.springframework.remoting.jaxws.JaxWsPortClientInterceptor.doInvoke(JaxWsPortClientInterceptor.java:580)
at org.springframework.remoting.jaxws.JaxWsPortClientInterceptor.doInvoke(JaxWsPortClientInterceptor.java:554)
... 56 more
Caused by: java.lang.IllegalArgumentException: prefix xsd is not bound to a namespace
at com.sun.xml.internal.bind.DatatypeConverterImpl._parseQName(DatatypeConverterImpl.java:355)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.selectLoader(LeafPropertyXsiLoader.java:75)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.LeafPropertyXsiLoader.startElement(LeafPropertyXsiLoader.java:58)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:559)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:229)
at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:266)
at com.sun.xml.internal.bind.unmarshaller.DOMScanner.visit(DOMScanner.java:235)
at com.sun.xml.internal.bind.unmarshaller.DOMScanner.scan(DOMScanner.java:112)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:354)
at com.sun.xml.internal.bind.v2.runtime.BridgeImpl.unmarshal(BridgeImpl.java:124)
at com.sun.xml.internal.bind.api.Bridge.unmarshal(Bridge.java:309)
at com.sun.xml.internal.ws.db.glassfish.BridgeWrapper.unmarshal(BridgeWrapper.java:217)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.getJAXBObject(SOAPFaultBuilder.java:304)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:135)
The response from the external service looks like the below (I have anonymized type names, but left everything else)
<env:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header/>
<env:Body>
<env:Fault>
<faultcode>env:Server</faultcode>
<faultstring>ERROR MESSAGE</faultstring>
<detail>
<n1:ProprietaryException xmlns:n1="java:com.company.service" xsi:type="n1:ProprietaryException">
<errorCode xsi:type="xsd:int">400</errorCode>
<errorReason xsi:type="xsd:string">Specific error</errorReason>
</n1:ProprietaryException>
</detail>
</env:Fault>
</env:Body>
</env:Envelope>
The problem is with the xsd:int and xsd:string in the faultCode and faultReason. It seems like the prefix/namespace declarations are not being inherited from the top level envelope when binding. The problem looks similar to this question except unlike that question this is about SOAP Fault handling, and in my case, the code is deep inside JAX-WS and JAXB so I have no idea how we could fix it or workaround it.
Unless the old code was relying on some behaviour that never should have worked, I can't help but conclude something has been broken between JAX-WS and JAXB in their Java 8 implementations.
Update (Jan 4 2016): I've also tried this with a CXF 3.1.4 client instead of the Metro RI. Same problem. It seems to be the same issue as mentioned here
Update (Jan 6 2016): I've narrowed this problem to a change introduced to the JAXB RI 2.2.6. Thus the problem can be replicated on Java 7 with a forced upgrade to JAXB RI 2.2.6. It seems it might relate to changes made in JAXB-890.
I have tested working around this in at least two different ways:
-Dcom.sun.xml.bind.improvedXsiTypeHandling=false
(or the equivalent .internal
property if using the bundled JDK JAXB RI) seems to workaround the issue. But I have no idea what this setting really does; or what the implications would be for the rest of the JAXB usage in my system.Any ideas for how to proceed here?
One workaround which seems to work (but should not be required and has other consequences for JAXB usage in other parts of my application which make it undesirable) is to replace the JAXB provider with EclipseLink MOXy (tested 1.6.2).
Given this works, it does seem that this is a problem in the JAXB RI (Metro) version included with Java 8 (up to at least 1.8.0u66).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With