2015-10-25 45 views
6

Mamy powiązanie JAX-WS/JAXB z zewnętrzną usługą sieciową, która działa poprawnie na Java 7 (1.7.0u80) z dołączonymi implementacjami referencyjnymi. Podczas migracji do środowiska Java 8 (1.8.0u66) wywołania usługi sieciowej ogólnie działają poprawnie, ale nie mogą już zawierać błędów SOAP i ich elementów szczegółów w wyjątkach Java z niestandardowymi szczegółami, podając przedrostek nie związany z błędem przestrzeni nazw."prefiks xsd nie jest powiązany z przestrzenią nazw" un-marszowanie SOAPFault z JAXB po migracji do Java 8

Niepowodzenie jest

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) 

odpowiedź z usługi zewnętrznej wygląda jak poniżej (mam anonimowe nazwy typu, ale pozostawił wszystko inne)

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

Problem jest z xsd : int i xsd: string w codeCode i faultReason. Wygląda na to, że deklaracje prefiksów/przestrzeni nazw nie są dziedziczone z obwiedni najwyższego poziomu podczas wiązania. Problem wygląda podobnie do this question, ale w przeciwieństwie do tego pytania dotyczy to obsługi protokołu SOAP, aw moim przypadku kod znajduje się głęboko w JAX-WS i JAXB, więc nie mam pojęcia, jak możemy go naprawić lub obejść go.

O ile stary kod nie polegał na pewnych zachowaniach, które nigdy nie powinny zadziałać, nie mogę nie wspomnieć, że coś zostało przerwane między JAX-WS i JAXB w ich implementacjach Java 8.

Aktualizacja (styczeń 4 2016): Próbowałem również tego z klientem CXF 3.1.4 zamiast Metro RI. Taki sam problem. Wydaje się, że ten sam problem jak wspomniano here

Update (Jan 6 2016): mam zawężony ten problem ze zmianą wprowadzoną do JAXB RI 2.2.6. W ten sposób problem można zreplikować na Java 7 z wymuszoną aktualizacją do JAXB RI 2.2.6. Wygląda na to, że może odnosić się do zmian wprowadzonych w JAXB-890.

Ja testowałem pracy wokół tego w co najmniej dwóch różnych sposobów:

  1. Use Java 8 z siłą JAXB zdegradowany z powrotem do 2.2.5 (wersja JAX-WS nie ma to znaczenia). Nie wydaje się dobrym długoterminowym rozwiązaniem.
  2. Znalazłem, że -Dcom.sun.xml.bind.improvedXsiTypeHandling=false (lub równoważna właściwość .internal, jeśli używają pakietu JDK JAXB RI) wydaje się obejść problem. Ale nie mam pojęcia, co tak naprawdę robi to ustawienie; lub jakie będą konsekwencje dla pozostałej części użytkowania JAXB w moim systemie.

Jakieś pomysły, jak tu postępować?

+1

Czy możesz przenieść deklarację 'xmlns: xsd =' z 'Koperta' do elementu' Usterka'? – Holger

+0

Niestety, nie bez jakiegoś hackowego hakowania Xml, bo usługa, do której dzwonię, nie jest moja. Nie wierzę, że coś jest nie tak z ich odpowiedzią, chociaż zgadzam się, że prawdopodobnie rozwiązałoby to problem. – Chad

Odpowiedz

1

Jeden obejście, które wydaje się działać (ale nie powinno być wymagane i ma inne konsekwencje dla JAXB wykorzystania w innych częściach mojej aplikacji, które sprawiają, że niepożądane) ma zastąpić dostawcę JAXB z EclipseLink Moxy (testowane 1.6.2).

Biorąc to pod uwagę, wydaje się, że jest to problem w wersji JAXB RI (Metro) dołączonej do Java 8 (do co najmniej 1.8.0u66).

0

Niedawno spotkałem się z podobnym problemem.Przełączenie na MOXy lub użycie pewnych niejasnych parametrów maszyny JVM nie wchodziło w grę, więc przyjrzałem się sposobom wdrożenia jakiegoś "hackowania przed lufą" wspomnianego powyżej.

Okazuje się, jeśli popełnisz SOAPHandler jak tak

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

a następnie dodać go do łańcucha procedury obsługi swojego klienta jak tak

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

wtedy wszystko cudownie działa i własności błędy SOAP dostać konwertowane na zastrzeżone wyjątki.

Nie wiem jeszcze, dlaczego to działa i czy łamie coś innego, ponieważ jest całkiem oczywiste, że nie wykonuję żadnej manipulacji XML wewnątrz handler'a (getter wywołuje tylko leniwą inicjalizację DOM dla koperty AFAICT).

EDYTOWANIE: po kolejnych testach odkryłem, że udało mi się to przejść w niektórych testach, ale aby zawieść w innych. Powrót do deski kreślarskiej ...