We have a JAX-WS / JAXB binding to an external web service that works fine in Java 7 (1.7.0u80) with reference implementations enabled. When migrating to Java 8 (1.8.0u66), web service calls usually work fine, however, it can no longer overclock SOAP errors and their drilldown items in Java exceptions with custom details, instead of a prefix that is not associated with a namespace error.
Error
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 external service response is as follows (I have anonymous type names, but everything else is left)
<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 xsd: int and xsd: string in faultCode and faultReason code. It seems that the prefix / namespace declarations are not inherited from the top-level envelope when binding. The problem is similar to this question , except that, unlike this question, it is about handling SOAP errors, and in my case the code is deep inside JAX-WS and JAXB, so I have no idea how we could fix it or get along with it.
If the old code did not rely on some behavior that should never have worked, I cannot help but conclude that something was broken between JAX-WS and JAXB in their Java 8 implementations.
Update (January 4, 2016) . I also tried this with the CXF 3.1.4 client instead of Metro RI. Same problem. This seems to be the same problem mentioned here
Update (January 6, 2016) . I narrowed down this issue to the change introduced in JAXB RI 2.2.6. Thus, the problem can be replicated in Java 7 with a forced upgrade to JAXB RI 2.2.6. It looks like this might relate to changes made to the JAXB-890 .
I tested working around this in at least two different ways:
- Use Java 8 with JAXB power downgraded to 2.2.5 (the JAX-WS version doesn't seem to matter). Doesn't seem like a good long-term solution.
- I found that
-Dcom.sun.xml.bind.improvedXsiTypeHandling=false (or the equivalent .internal property when using the associated JAXB RI JDK) seems to work around the problem. But I have no idea what this setting really does; or what the consequences will be for the rest of using JAXB on my system.
Any ideas on how to proceed here?