Msgstr "xsd prefix not mapped to namespace" un-marshalling SOAPFault with JAXB after migrating to Java 8

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?

+6
source share
2 answers

One way that seems to work (but should not be required and has other implications for using JAXB in other parts of my application, which makes it undesirable) is to replace the JAXB provider EclipseLink MOXy (tested 1.6.2).

Given that this works, it looks like this is a problem in the JAXB RI (Metro) version included in Java 8 (up to at least 1.8.0u66).

+1
source

Recently, I encountered a similar problem. Switching to MOXy or using some obscure JVM parameters was not an option, so I looked at ways to implement the kind of “preliminary hacks” mentioned above.

It turns out if you make SOAPHandler this way

 public class NamespaceBindingShim implements SOAPHandler<SOAPMessageContext> { @Override public boolean handleMessage(SOAPMessageContext context) { return true; } @Override public boolean handleFault(SOAPMessageContext context) { context.getMessage(); return true; } @Override public void close(MessageContext context) { } @Override public Set<QName> getHeaders() { return null; } } 

and then add it to your client’s handler chain this way

 ServicePort port = service.getServicePort(); BindingProvider bindingProvider = (BindingProvider) port; Binding binding = bindingProvider.getBinding(); binding.setHandlerChain(Collections.singletonList(new NamespaceBindingShim())); 

then everything works miraculously, and native SOAP errors are converted to native exceptions.

I don’t know yet why this works, and that it breaks something else, since it’s pretty obvious that I don’t do any XML manipulations inside the handler (getter only causes lazy DOM initialization for the AFAICT envelope).

EDIT: after more testing, I found that it went through in some tests, but with an error in others. Back to the drawing board ...

0
source

All Articles