2012-01-11 24 views
9

Tôi thực sự gặp phải một vấn đề thực sự khó chịu với TestNG và RESTeasy.java.lang.LinkageError: ClassCastException

Tôi có một lớp chạy một số thử nghiệm đối với lớp API sử dụng khung RESTeasy để lộ chính nó.

Tuy nhiên nếu tôi để cho chạy thử với maven (thử nghiệm mvn), sau đó tôi nhận được ngoại lệ sau đây:

java.lang.LinkageError: ClassCastException: attempting to castjar:file:/C:/Users/rit/.m2/repository/org/jboss/resteasy/jaxrs-api/2.3.0.GA/jaxrs-api-2.3.0.GA.jar!/javax/ws/rs/ext/RuntimeDelegate.classtojar:file:/C:/Users/rit/.m2/repository/org/jboss/resteasy/jaxrs-api/2.3.0.GA/jaxrs-api-2.3.0.GA.jar!/javax/ws/rs/ext/RuntimeDelegate.class 
at javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:126) 
at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:96) 
at javax.ws.rs.core.Response$ResponseBuilder.newInstance(Response.java:394) 
at javax.ws.rs.core.Response.status(Response.java:116) 
at javax.ws.rs.core.Response.status(Response.java:130) 
at com.pd.api.TokenAPI_V1.validateAccessToken(TokenAPI_V1.java:141) 
at com.test.pd.api.TokenAPI_V1Test.testIfValidAccessTokenReturnsCorrectHTTPHeadersWhenTokenIsNotFound(TokenAPI_V1Test.java:359) 

Xét nghiệm này không gì hơn là gọi một phương thức của obejct API trả về một đối tượng Response (từ RESTeasy). Là khung kiểm thử, tôi sử dụng TestNG.

Phương pháp thử

@Test 
public void testIfValidAccessTokenReturnsCorrectHTTPHeadersWhenTokenIsNotFound() throws InvalidAccessTokenException { 
    Mockito.when(tokenService.validateAccessToken(TestConstants.ACCESS_TOKEN)).thenThrow(new InvalidAccessTokenException()); 

    Response response = tokenAPI_v1.validateAccessToken(TestConstants.ACCESS_TOKEN, TestConstants.USER_AGENT); 
    assert "no-store".equals(response.getMetadata().getFirst("Cache-Control")); 
    assert "no-cache".equals(response.getMetadata().getFirst("Pragma")); 
} 

Issue Mô tả

Dường như khuôn khổ RESTeasy tải RuntimeDelegate trong một bộ nạp lớp khác nhau. Nếu tôi xem xét mã nguồn, thì có phương thức sau tại RuntimeDelegate (bao gồm dòng 126): RuntimeDelegate.java.

Vì vậy, các tuyên bố chính có liên quan đến lỗi này là việc kiểm tra instanceof:

if (!(delegate instanceof RuntimeDelegate)) 

Nếu tôi kiểm tra classloader của thể hiện ủy nhiệm vs classloader của RuntimeDelegate, sau đó tôi nhận được đầu ra sau đây:

delegate.getClass().getClassLoader() -> [email protected] 

RuntimeDelegate.class.getClassLoader() -> [email protected] 

Tôi biết rằng điều này tất nhiên không hiệu quả nhưng tôi tự hỏi tại sao các công cụ RESTeasy được tải trong MockClassLoader chứ không phải trong một MockClassLoader khác. Đặc biệt là tôi không chế nhạo TokenAPI được kiểm tra.

kiện Strange

Điều kỳ lạ là, khi tôi chạy thử nghiệm ra khỏi IntelliJ (tôi chỉ chọn để chạy tất cả các bài kiểm tra từ lớp trao, trong đó có phương pháp nào tạo ra lỗi), sau đó nó chạy qua. Dường như nó là bằng cách nào đó liên quan đến thực tế là thử nghiệm mvn chạy tất cả các bài kiểm tra từ dự án maven (hoặc ít nhất đó là những gì tôi đoán).

+0

Ít nhất tôi đã tìm ra cách để chạy thử nghiệm lần nữa: Một trong các thử nghiệm sử dụng PowerMockito và như đã nêu trong trình tải lớp ở trên, bằng cách nào đó PowerMockito đã tải các lớp bên dưới gói jagax.ws. Để vô hiệu hóa PowerMockito để tải các lớp học, tôi đã thêm gói javax.ws vào chú thích PowerMockitoIgnore: ({ "javax.ws *"}) @PowerMockIgnore Tôi vẫn không nhận được lý do tại sao kiểm tra không sử dụng trình nạp lớp được cung cấp bởi PowerMockito. Điều này có liên quan đến TestNG không? – rit

+1

Hi rit, nó thực sự phụ thuộc vào những lớp học được nạp trước bởi bộ nạp lớp hệ thống trước hay không. Mã của bạn chắc chắn tham khảo một số lớp JAX-WS, mà có thể tham khảo các classe khác trong JAX-WS. JVM thực hiện liên kết sau để tránh tải không cần thiết khi khởi động. Vì vậy, khi các lớp này được sử dụng lần đầu tiên chúng được nạp bởi trình nạp lớp PowerMock, nhưng khi RESTeasy được khởi động, nó được nạp bằng cách sử dụng trình nạp lớp hệ thống, sau đó loại được so sánh (instanceof) chúng khác nhau, vì chúng được nạp khác nhau bộ nạp lớp. Giải pháp của bạn là giải pháp phù hợp. – Brice

+1

Nếu giải pháp của bạn hoạt động và là giải pháp phù hợp, bạn có thể trả lời câu hỏi của riêng mình. – Luciano

Trả lời

6

Rất tiếc, tôi không thể cho bạn biết lý do điều này xảy ra, nhưng tôi có thể cho bạn biết cách giải quyết vấn đề này.

Vấn đề là, PowerMockito đã quét đường dẫn lớp tha và cũng đã thêm các lớp RESTeasy (nằm trong gói 'javax.ws. *' .Đối với RuntimeDelegate được đề cập ở trên đã được tải bởi trình nạp lớp PowerMockito và gây ra sau này . vấn đề, rằng lớp được so sánh với một từ một classloader khác nhau

để khắc phục vấn đề này, hãy cho PowerMockito để bỏ qua các gói javax.ws khi quét cho các lớp:

@PowerMockIgnore({"javax.ws.*"}) 
1

tôi phải đối mặt với cùng một vấn đề khi triển khai ứng dụng của tôi lên JBoss v6.1 - bằng cách nào đó đã hiểu được vấn đề đó do cấu trúc gói giống nhau của lớp RuntimeDelegate.class tồn tại trong jesrey-core và jboss 'jaxrs-api jar

Dưới đây là pom của tôi.xml

<!-- For Restful Client --> 
    <dependency> 
     <groupId>com.sun.jersey</groupId> 
     <artifactId>jersey-client</artifactId> 
     <version>1.8</version> 
     <exclusions> 
      <exclusion> 
       <groupId>com.sun.jersey</groupId> 
       <artifactId>resteasy-jaxrs</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 

    <!-- For Jackson (JSON Utility) --> 
    <dependency> 
     <groupId>org.codehaus.jackson</groupId> 
     <artifactId>jackson-mapper-asl</artifactId> 
     <version>1.8.5</version> 
    </dependency> 

    <dependency> 
     <groupId>com.sun.jersey</groupId> 
     <artifactId>jersey-json</artifactId> 
     <version>1.9</version> 
     <exclusions> 
      <exclusion> 
       <groupId>com.sun.jersey</groupId> 
       <artifactId>jersey-core</artifactId> 
      </exclusion> 
     </exclusions> 
    </dependency> 

Sau khi chiến tranh của tôi được triển khai lên JBoss, chỉ cần xóa thư mục resteasy.deployer khỏi thư mục jboss 'server \ default \ deployers. Chạy ứng dụng của tôi và nó hoạt động.

Tôi sẽ rất vui nếu ai đó giải thích lý do lỗi này được giải quyết theo cách này? (Tôi nghĩ rằng JBoss 'đã không cần thiết được vận chuyển với các lọ resteasy.deployers khi các nhà phát triển có thể bao gồm các lọ của riêng mình trong các ứng dụng của họ) - Không che giấu rằng tôi đã cố gắng triển khai chiến tranh của tôi trên Tomcat và nó hoạt động trơn tru.