2015-09-22 41 views
6

Tôi có máy khách dịch vụ web JaxWS đã chạy thành công trong Java 6 trong nhiều năm. Bây giờ khi Java được nâng cấp lên phiên bản 8, chúng tôi đang nhận được NullPointerException khi nhận cổngMáy khách webservice của JaxWS cho Java 6 không hoạt động trong Java 8

java.lang.NullPointerException 
    at com.sun.xml.internal.ws.client.ClientContainer$1.getResource(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.MetroConfigLoader.locateResource(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.MetroConfigLoader.locateResource(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.MetroConfigLoader.init(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.MetroConfigLoader.<init>(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.TubelineAssemblyController.getTubeCreators(Unknown Source) 
    at com.sun.xml.internal.ws.assembler.MetroTubelineAssembler.createClient(Unknown Source) 
    at com.sun.xml.internal.ws.client.Stub.createPipeline(Unknown Source) 
    at com.sun.xml.internal.ws.client.Stub.<init>(Unknown Source) 
    at com.sun.xml.internal.ws.client.Stub.<init>(Unknown Source) 
    at com.sun.xml.internal.ws.client.Stub.<init>(Unknown Source) 
    at com.sun.xml.internal.ws.client.sei.SEIStub.<init>(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.getStubHandler(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.createEndpointIFBaseProxy(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(Unknown Source) 
    at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(Unknown Source) 
    at javax.xml.ws.Service.getPort(Unknown Source) 
    at myclient.stub.MyService.<init>(MyService.java:38) 

Tôi đã thử chạy nó với Java 7 phiên bản 1.7.0_80 và ở đó nó cũng làm việc nhưng phiên bản đầu tiên của Java 8 nguyên nhân này ngoại lệ.

Tôi đã đập đầu của tôi với điều này một thời gian khá bây giờ vì vậy nếu ai đó có thể cho tôi bất kỳ manh mối nơi để bắt đầu sửa chữa này nó sẽ thực sự tuyệt vời.

Đây là WSDL, tôi đã chỉnh sửa nó một chút vì đó không phải là dịch vụ của tôi nhưng hy vọng là đủ?

<?xml version="1.0" encoding="utf-8" standalone="no"?> 
<wsdl:definitions xmlns:ns1="http://www.dummyservice/sample/interface" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="Sample" 
     targetNamespace="http://www.dummyservice/sample/interface"> 
    <wsdl:types> 
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" 
    targetNamespace="http://www.dummyservice/sample/interface" xmlns="http://www.dummyservice/sample/interface" 
    elementFormDefault="qualified" jaxb:version="2.0"> 
     <xs:element name="PersonQuery"> 
     <xs:complexType> 
      <xs:sequence> 
      <xs:element name="system" type="xs:string" /> 
      <xs:element name="user" type="xs:string" /> 
      </xs:sequence> 
     </xs:complexType> 
     </xs:element> 
     <xs:element name="PersonReply"> 
     <xs:complexType> 
      <xs:sequence> 
      <xs:element name="Header" type="HeaderType" /> 
      <xs:element name="person" type="PersonType" minOccurs="0" maxOccurs="1" /> 
      <xs:element name="address" type="AddressType" minOccurs="0" maxOccurs="unbounded" /> 
      </xs:sequence> 
     </xs:complexType> 
     </xs:element> 
     <xs:complexType name="HeaderType"> 
     <xs:sequence> 
      <xs:element name="tila" type="StatusType" /> 
     </xs:sequence> 
     </xs:complexType> 
     <xs:simpleType name="StatusType"> 
     <xs:annotation> 
      <xs:appinfo> 
      <jaxb:typesafeEnumClass> 
       <jaxb:typesafeEnumMember name="SUCCESS" value="0001" /> 
       <jaxb:typesafeEnumMember name="FAIL" value="0000" /> 
      </jaxb:typesafeEnumClass> 
      </xs:appinfo> 
     </xs:annotation> 
     <xs:restriction base="xs:string"> 
      <xs:enumeration value="0000" /> 
      <xs:enumeration value="0001" /> 
     </xs:restriction> 
     </xs:simpleType> 
     <xs:complexType name="PersonType"> 
     <xs:sequence> 
      <xs:element name="firstname" type="xs:string" minOccurs="0" /> 
      <xs:element name="lastname" type="xs:string" minOccurs="0" /> 
     </xs:sequence> 
     </xs:complexType> 
     <xs:complexType name="AddressType"> 
     <xs:sequence> 
      <xs:element name="addresstype" type="AddresstypeType" minOccurs="0" /> 
      <xs:element name="streetaddress" type="xs:string" minOccurs="0" /> 
      <xs:element name="city" type="xs:string" minOccurs="0" /> 
      <xs:element name="postalcode" type="xs:string" minOccurs="0" /> 
     </xs:sequence> 
     </xs:complexType> 
     <xs:simpleType name="AddresstypeType"> 
     <xs:annotation> 
      <xs:appinfo> 
      <jaxb:typesafeEnumClass> 
       <jaxb:typesafeEnumMember name="HOME" value="001" /> 
       <jaxb:typesafeEnumMember name="OFFICE" value="002" /> 
      </jaxb:typesafeEnumClass> 
      </xs:appinfo> 
     </xs:annotation> 
     <xs:restriction base="xs:string"> 
      <xs:enumeration value="001" /> 
      <xs:enumeration value="002" /> 
     </xs:restriction> 
     </xs:simpleType> 
    </xs:schema> 
    </wsdl:types> 
    <wsdl:message name="PersonQueryOperationRequest"> 
    <wsdl:part element="ns1:PersonQuery" name="parameters" /> 
    </wsdl:message> 
    <wsdl:message name="PersonQueryOperationResponse"> 
    <wsdl:part element="ns1:PersonReply" name="parameters" /> 
    </wsdl:message> 
    <wsdl:portType name="SamplePort"> 
    <wsdl:operation name="PersonQueryOperation"> 
     <wsdl:input message="ns1:PersonQueryOperationRequest" /> 
     <wsdl:output message="ns1:PersonQueryOperationResponse" /> 
    </wsdl:operation> 
    </wsdl:portType> 
    <wsdl:binding name="SampleSOAP" type="ns1:SamplePort"> 
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> 
    <wsdl:operation name="PersonQueryOperation"> 
     <soap:operation soapAction="http://www.dummyservice/sample/interface/SampleOperation" /> 
     <wsdl:input> 
     <soap:body use="literal" /> 
     </wsdl:input> 
     <wsdl:output> 
     <soap:body use="literal" /> 
     </wsdl:output> 
    </wsdl:operation> 
    </wsdl:binding> 
    <wsdl:service name="SampleService"> 
    <wsdl:port binding="ns1:SampleSOAP" name="Sample"> 
     <soap:address location="https://127.0.0.1/data/ws" /> 
    </wsdl:port> 
    </wsdl:service> 
</wsdl:definitions> 

Chỉnh sửa: Tải lớp có vẻ là vấn đề, cả trình nạp lớp ngữ cảnh và trình nạp lớp lớp đều rỗng trong ClientContainer đó.

private final ResourceLoader loader = new ResourceLoader() { 
public URL More ...getResource(String resource) throws MalformedURLException { 
     ClassLoader cl = Thread.currentThread().getContextClassLoader(); 
    if (cl == null) { 
     cl = this.getClass().getClassLoader(); 
    } 
    return cl.getResource("META-INF/"+resource); 
} 
}; 

Khi chúng tôi đặt rõ ràng trình nạp lớp hệ thống vào trình nạp lớp ngữ cảnh trước khi gọi ws gọi nó bắt đầu hoạt động. Nhưng đó là sửa chữa tốt cho điều này? Tôi tự hỏi tại sao điều này đã ngừng làm việc trong Java8 và điều này có thể là một vấn đề trong việc thực hiện ws của họ?

Kính trọng,

Janne

+0

Bạn có thể chỉnh sửa câu hỏi của mình để bao gồm WSDL, vì vậy chúng tôi có thể cố gắng tạo lại vấn đề không? – VGR

+0

Tôi đã bao gồm WSDL, tôi đã phải chỉnh sửa nó để phân biệt nó với bản gốc nhưng hy vọng rằng đó là ok. –

+0

Dường như cách duy nhất [phương thức đó] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/xml/nội bộ/ws/client/ClientContainer.java # ClientContainer.0loader) có thể ném NullPointerException là khi lớp được nạp bởi hệ thống ClassLoader (vì [ Java được phép trả về null để chỉ ra hệ thống ClassLoader (http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getClassLoader--)). Bạn đang chạy hệ điều hành nào? Bạn đã thử sử dụng phiên bản Java mới nhất chưa? – VGR

Trả lời

1

Cố gắng tạo ra các khai cho khách hàng webservice một lần nữa trong Java8.

Nói chung, chúng tôi tạo một cái bình đựng và đặt nó trong đường dẫn lớp. Do Java tương thích ngược, chúng tôi bỏ qua bước này khi tạo lại jar khi nâng cấp lên phiên bản cao hơn.

Nhưng vì đối với Java 6 & 7 hoạt động và chỉ thất bại trong Java 8, tôi khuyên bạn nên tạo lại Sơ khai để loại bỏ bất kỳ trục trặc nào trong khả năng tương thích ngược của Java 8.

+0

Tôi đã tạo chúng với Java 8 nhưng không có hiệu lực. –

4

Chúng tôi đã gặp sự cố này (cùng một dấu vết ngăn xếp và tất cả) sau khi nâng cấp từ Java 6 lên Java 8. Tôi sẽ đăng giải pháp của chúng tôi trước, sau đó là giải thích bổ sung.

Đối với chúng tôi, các điều kiện chính, theo đó vấn đề này xảy ra là:

  1. Java 8 chạy như một JVM nhúng qua jvm.dll từ bên trong một chương trình Windows. Tôi đã cố gắng để tái tạo các vấn đề đang chạy trong một Java 8 độc lập JVM và tôi không thể làm cho nó xảy ra. Chạy độc lập là rất hữu ích trong việc chẩn đoán vấn đề, tuy nhiên.
  2. Sử dụng phương thức proxy để khởi tạo kết nối với dịch vụ web JAX-WS, tạo động lực sơ khai ở phía máy khách bằng cách sử dụng WSDL được lưu trữ ở phía máy chủ.

Cách giải quyết:

Khi bạn gọi cuộc gọi đến Service.getPort(Class<T>) nó cần phải được thực hiện trong chủ đề của riêng mình, tách biệt với chủ đề mà bạn có cuộc gọi chạy trong trước đó. Điều này cho phép bạn là một cơ hội để đặt ClassLoader trên luồng đó thành một ClassLoader không phải là trình nạp lớp bootstrap, đó là điểm mấu chốt của vấn đề trong ClientContainer.java (giải thích thêm về điều đó bên dưới).Dưới đây là một số mã mẫu đang hoạt động cho chúng tôi. Bạn sẽ phải sửa đổi nó cho phù hợp với nhu cầu của bạn.

public class YourClass { 
    private YourWebService yourWebService; 

    // You may want to synchronize on this method depending on your use case 
    public YourWebService getYourWebService() { 
    if (this.yourWebService == null) { 
     // We create a thread so that we can set the ClassLoader 
     Thread t = new Thread() { 
     public void run() { 
      synchronized(this) { 
      // Get the string of your webservice WSDL from somewhere 
      String url = "http://YOURHOST:YOURPORT/your-web-service/YourWebService?wsdl"; 
      URL srvUrl = null; 
      try { 
       srvUrl = new URL(url); 
      } catch (MalformedURLException ex) { 
       throw new RuntimeException(String.format("Malformed URL: %s", url), ex); 
      } 

      QName qName = new QName("your-webservice-namespace", "YourWebServiceName"); 
      Service service = Service.create(srvUrl, qName); 
      this.yourWebService = service.getPort(YourWebService.class); 
      notify(); 
      } 
     } 
     }; 

     // Thread.currentThread().getContextClassloader() 
     // returns null in com.sun.xml.internal.ws.client.ClientContainer. 
     // (See http://hg.openjdk.java.net/jdk8/jdk8/jaxws/file/d03dd22762db/src/share/jaxws_classes/com/sun/xml/internal/ws/client/ClientContainer.java, lines 39-47) 
     // To work around that, I force setting of the ContextClassLoader 
     // on this thread (in which the Service.getPort() method will run) so 
     // that when ClientContainer calls Thread.currentThread().getContextClassLoader(), it doesn't get a null 
     // (i.e., the bootstrap classloader). 
     // 
     t.setContextClassLoader(YourClass.class.getClassLoader()); 
     t.start(); 
     // Wait until above thread completes in order to return yourWebService 
     synchronized(t) { 
     try { 
      t.wait(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     } 
    } 

    return this.yourWebService; 
    } 
} 

Bối cảnh bổ sung và chi tiết:

Khó khăn trong việc chẩn đoán này đối với chúng tôi là vấn đề chỉ xảy ra bên trong một sản phẩm Windows mà ra mắt một JVM nhúng. Nếu không có remote debugging trên JVM đó, sẽ mất nhiều thời gian hơn để đến cuối vấn đề. Khi tôi thấy rằng 1) khi tôi chạy cùng một mã gọi lời gọi đến Service.getPort(Class<T>) bên trong một JVM độc lập (bên ngoài sản phẩm Windows) và, 2) lớp ClientContainer có thể lấy Trình nạp lớp của chuỗi hiện tại và, 3) mà ClassLoader trả về không phải là BootLoader bootstrap (tức là, không phải là null), nó làm cho tôi nhận ra rằng tôi phải tìm một cách để đảm bảo rằng luồng mà ClientContainer đang chạy sẽ không nhận được ClassLoader khởi động. Mục tiêu sau đó đã trở thành để xem liệu tôi có thể tìm cách thay đổi ClassLoader được giải quyết bằng mã số ClientContainer hay không.

ClientContainer nguồn: http://hg.openjdk.java.net/jdk8/jdk8/jaxws/file/d03dd22762db/src/share/jaxws_classes/com/sun/xml/internal/ws/client/ClientContainer.java

Lưu ý trong nguồn ClientContainer rằng có hai nỗ lực để giải quyết một classloader. Vấn đề là nếu cả hai những nỗ lực trả lại classloader bootstrap, một NullPointerException sẽ cho kết quả trên dòng 45 từ cl sẽ được null:

cl.getResource("META-INF/"+resource); 

workaround này đảm bảo rằng các classloader giải quyết bằng mã ClientContainer sẽ là classloader mà bạn đặt trên chuỗi của mình.

Tôi đã đệ trình một vé cho đội JAX-WS để điều tra vấn đề ở đây: https://java.net/jira/browse/JAX_WS-1178

1

tôi đi qua cùng một vấn đề sau khi nâng cấp lên Java 8. @ câu trả lời 2AGuy của sẽ giúp rất nhiều. Tuy nhiên, vấn đề đã diễn ra cả khi chạy trên Mac và Linux cho tôi. Và có thể có một phiên bản đơn giản hơn để giải quyết vấn đề. Mã của bạn có thể thực hiện dưới đường trước khi gọi getPort():

Thread.currentThread().setContextClassLoader(XXX.class.getClassLoader());

này sẽ thay thế các chủ đề bối cảnh lớp nạp từ Bootstrap lớp loader để bất cứ ai mà bạn đặt nó vào được, mà không có chi phí để tạo ra một chủ đề mới chỉ để đặt classLoader.

Nguyên nhân gốc rễ của điều này vẫn là điều bí ẩn đối với tôi. Nghi ngờ của tôi là thread tạo proxy máy khách dịch vụ SOAP (một Service Endpoint Proxy trong ngữ cảnh tài liệu) là luồng chính hoặc được tạo bởi nó, classLoader của nó là trình nạp lớp bootstrap, được nạp trong giai đoạn sớm nhất khi JVM khởi động. Dựa trên tài liệu Java cho Class#getClassLoader(), một NullPointer xuất hiện.

Một số triển khai có thể sử dụng null để trình bày trình nạp lớp khởi động. Phương thức này sẽ trả về null trong các triển khai như vậy nếu lớp này được nạp bởi trình nạp lớp bootstrap.

+1

Cho người đàn ông đó một cookie! –

Các vấn đề liên quan