2015-10-25 5 views
6

Wir haben eine JAX-WS/JAXB-Bindung an einen externen Webservice, der auf Java 7 (1.7.0u80) funktioniert) mit den mitgelieferten Referenzimplementierungen. Während der Migration zu Java 8 (1.8.0u66) funktionieren die Web-Service-Aufrufe in der Regel OK, jedoch können SOAP-Fehler und ihre Detailelemente nicht mehr mit Java-Ausnahmen mit benutzerdefinierten Details entfernt werden, sondern ein Präfix, das nicht an einen Namespace-Fehler gebunden ist."Präfix xsd ist nicht an einen Namespace gebunden" SOAPFault mit JAXB nach Migration nach Java 8 migrieren

Das Scheitern ist

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) 

Die Antwort des externen Service sieht aus wie unter dem (ich habe Typnamen anonymisiert, aber alles andere links)

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

Das Problem ist, mit dem xsd : int und xsd: string im faultCode und faultReason. Es scheint, dass die Präfix-/Namespace-Deklarationen nicht von der obersten Ebene der Hüllkurve beim Binden übernommen werden. Das Problem sieht ähnlich wie this question aus, aber im Gegensatz zu dieser Frage handelt es sich um SOAP Fault Handling, und in meinem Fall ist der Code tief in JAX-WS und JAXB, also habe ich keine Ahnung, wie wir es reparieren oder umgehen können.

Wenn sich der alte Code nicht auf ein Verhalten verlassen hat, das nie hätte funktionieren sollen, kann ich nicht anders, als zu schlussfolgern, dass in ihren Java-8-Implementierungen zwischen JAX-WS und JAXB etwas gebrochen wurde.

Update (4. Januar 2016): Ich habe das auch mit einem CXF 3.1.4 Client anstelle der Metro RI versucht. Gleiches Problem. Es scheint, das gleiche Problem zu sein, wie here erwähnte

Update (6. Januar 2016): Ich habe dieses Problem auf eine an die JAXB RI 2.2.6 eingeführte Änderung verengt haben. Somit kann das Problem auf Java 7 mit einem erzwungenen Upgrade auf JAXB RI 2.2.6 repliziert werden. Es scheint sich um Änderungen in JAXB-890 zu handeln.

Ich habe getestet in mindestens zwei verschiedenen Möglichkeiten, um dieses Arbeits:

  1. Verwenden Java 8 mit JAXB Kraft degradiert zurück zu 2.2.5 (JAX-WS-Version scheint nicht Rolle). Scheint keine gute langfristige Lösung.
  2. Ich fand, dass -Dcom.sun.xml.bind.improvedXsiTypeHandling=false (oder die gleichwertige .internal Eigenschaft, wenn Sie das gebündelte JDK JAXB RI verwenden) scheint das Problem zu umgehen. Aber ich habe keine Ahnung, was diese Einstellung wirklich macht; oder was die Implikationen für den Rest der JAXB-Nutzung in meinem System wären.

Irgendwelche Ideen für, wie man hier vorgeht?

+1

Können Sie die 'xmlns: xsd =' Deklaration von der 'Envelope' zum' Fault' Element verschieben? – Holger

+0

Leider nicht ohne irgendeine Art von Vor-Unmarshall Xml-Hack, da der Dienst, den ich anrufe, nicht meiner ist. Ich glaube nicht, dass irgendetwas mit ihrer Antwort falsch ist, obwohl ich zustimme, dass dies das Problem wahrscheinlich lösen würde. – Chad

Antwort

1

Eine Abhilfe, die zu funktionieren scheint (sollte aber nicht erforderlich und hat andere Konsequenzen für JAXB Verwendung in anderen Teilen meiner Anwendung, die es nicht wünschenswert machen) ist es, die JAXB Anbieter mit Eclipse moxy (ersetzen getestet 1.6.2).

Vor diesem Hintergrund scheint es, dass dies ein Problem in der JAXB RI (Metro) Version ist, die in Java 8 enthalten ist (bis zu mindestens 1.8.0u66).

0

Konfrontiert mit einem ähnlichen Problem vor kurzem.Es war keine Option, zu MOXy zu wechseln oder einige obskure JVM-Parameter zu verwenden. Daher habe ich nach Möglichkeiten gesucht, einen "Prä-Unmarshall-Hack" zu implementieren, der oben erwähnt wurde.

Es stellte sich heraus, wenn Sie ein SOAPHandler machen wie 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; 
    } 
} 

und sie dann an die wie

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

dann wie durch ein Wunder funktioniert und bekommen alles so Handler Kette Ihres Client hinzufügen Fehler proprietären SOAP in proprietäre Ausnahmen konvertiert.

Ich weiß noch nicht, warum das funktioniert und ob es etwas anderes bricht, da es ziemlich offensichtlich ist, dass ich keine XML-Manipulation im Handler mache (der Getter ruft nur Lazy-DOM-Initialisierung für die Hülle AFAICT auf).

EDIT: nach mehr Tests habe ich festgestellt, dass dies in einigen Tests passieren, aber in anderen fehlschlagen. Zurück zum Zeichenbrett ...

Verwandte Themen