"prefix xsd is not bound to a namespace" un-marshalling SOAPFault with JAXB after migration to Java 8
Asked Answered
S

2

7

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:

  1. Use Java 8 with JAXB force downgraded back to 2.2.5 (JAX-WS version doesn't seem to matter). Doesn't seem a good long-term solution.
  2. I found that -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?

Scout answered 25/10, 2015 at 9:11 Comment(2)
Can you move the xmlns:xsd= declaration from the Envelope to the Fault element?Photomechanical
Unfortunately, not without some kind-of pre-unmarshall Xml hack, as the service I am calling is not mine. I don't believe there is anything wrong with their response, although I agree that would probably solve the issue here.Scout
S
1

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).

Scout answered 28/10, 2015 at 0:29 Comment(0)
M
0

Faced a similar issue recently. Switching to MOXy or using some obscure JVM parameters wasn't an option, so I looked on ways to implement some sort of a "pre-unmarshall hack" mentioned above.

Turns out, if you make a SOAPHandler like so

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 the handler chain of your client like so

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

then everything miraculously works and proprietary SOAP faults get converted to proprietary exceptions.

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

EDIT: after more testing I have discovered this to pass in some tests, but to fail in others. Back to the drawing board...

Merari answered 5/7, 2016 at 21:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.