2015-07-07 19 views
6

Tôi muốn chặn một số cuộc gọi phương thức trên một trong các lớp của tôi nhưng các lớp đó không có hàm tạo mặc định.Cách tạo một hàm tạo mặc định với Byte Buddy

Cho lớp sau, tôi sẽ thiết lập Byte Buddy như thế nào để tạo một hàm tạo không đối số công khai để có thể tạo lớp được tạo ra?

public class GetLoggedInUsersSaga extends AbstractSpaceSingleEventSaga { 
    private final UserSessionRepository userSessionRepository; 

    @Inject 
    public GetLoggedInUsersSaga(final UserSessionRepository userSessionRepository) { 
     this.userSessionRepository = userSessionRepository; 
    } 

    @StartsSaga 
    public void handle(final GetLoggedInUsersRequest request) { 
     // this is the method in want to intercept 
    } 
} 

EDIT: Trường hợp sử dụng bê tông để đơn giản hóa thiết lập thử nghiệm đơn vị.
Hiện nay chúng tôi luôn phải viết một cái gì đó như thế này:

@Test 
public void someTest() { 
    // Given 

    // When 
    GetLoggedInUsersRequest request = new GetLoggedInUsersRequest(); 
    setMessageForContext(request); // <-- always do this before calling handle 
    sut.handle(request); 

    // Then 
} 

Tôi nghĩ rằng nó sẽ được tốt đẹp để tạo ra một proxy trong phương pháp @Before có thể tự động thiết lập bối cảnh cho bạn.

@Before 
public void before() { 
    sut = new GetLoggedInUsersSaga(someDependency); 
    sut = intercept(sut); 
} 

@Test 
public void someTest() { 
    // Given 

    // When 
    GetLoggedInUsersRequest request = new GetLoggedInUsersRequest(); 
    sut.handle(request); 

    // Then 
} 

tôi đã chơi xung quanh một chút nhưng tiếc là tôi didnt làm cho nó làm việc ..

public <SAGA extends Saga> SAGA intercept(final SAGA sagaUnderTest) throws NoSuchMethodException, IllegalAccessException, InstantiationException { 
    return (SAGA) new ByteBuddy() 
      .subclass(sagaUnderTest.getClass()) 
      .defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC) 
      .intercept(MethodCall.invokeSuper()) 
      .method(ElementMatchers.isAnnotatedWith(StartsSaga.class)) 
      .intercept(
        MethodDelegation.to(
          new Object() { 
           @RuntimeType 
           public Object intercept(
             @SuperCall Callable<?> c, 
             @Origin Method m, 
             @AllArguments Object[] a) throws Exception { 
            setMessageForContext((Message) a[0]); 
            return c.call(); 
           } 
          })) 
      .make() 
      .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) 
      .getLoaded() 
      .newInstance(); 
} 

Đáng tiếc là bây giờ tôi nhận được (có lẽ vì gọi ctor vẫn là không chính xác cài đặt)

java.lang.IllegalStateException: Cannot invoke public com.frequentis.ps.account.service.audit.GetLoggedInUsersSaga$ByteBuddy$zSZuwhtR() as a super method 

Đây có phải là cách tiếp cận chính xác không?
Tôi có nên sử dụng byte buddy ở đây hoặc có cách nào khác dễ hơn không?

Trả lời

3

Bạn không thể xác định hàm tạo mà không có bất kỳ mã byte nào. Đây sẽ là một nhà xây dựng trừu tượng những gì là bất hợp pháp trong Java. Tôi sẽ thêm một mô tả chính xác hơn cho javadoc cho một phiên bản trong tương lai. Cảm ơn vì đã mang đến sự chú ý của tôi.

Bạn cần phải xác định một phương pháp gọi siêu mà là cần thiết cho bất kỳ constructor:

DynamicType.Builder builder = ... 
builder = builder 
    .defineConstructor(Collections.<Class<?>>emptyList(), Visibility.PUBLIC) 
    .intercept(MethodCall 
       .invoke(superClass.getDeclaredConstructor()) 
       .onSuper()) 

Đối với Thời tiết bạn nên sử dụng Byte Buddy đây: Tôi không thể cho bạn biết từ mã nhỏ, tôi đã nhìn thấy. Câu hỏi mà bạn nên hỏi: Liệu nó có làm cho mã của tôi dễ dàng hơn, cả hai đều xem xét số lượng mã và độ phức tạp của việc theo dõi nó? Nếu Byte Buddy làm cho mã của bạn dễ sử dụng hơn (và chạy), hãy sử dụng nó. Nếu không, đừng dùng nó.

+0

Cảm ơn câu trả lời của bạn, tôi đã chỉnh sửa câu hỏi của mình để hiển thị trường hợp sử dụng cụ thể cho việc này. Có lẽ bạn có một vài phút còn lại để giải thích những gì tôi đang làm sai. – leozilla

+0

Tăng đột biến. Nên đọc * javadoc của riêng tôi *. Bạn cần xác định hàm tạo để được gọi và cung cấp các đối số nếu chúng được yêu cầu. Bằng cách này, Byte Buddy không cần đoán. Bạn cũng có thể xem 'MethodCallTest' để xem ví dụ. –

+0

Tôi không hiểu. Bạn có khả năng gọi trình nạp lớp mặc định nếu trình nạp lớp bytebuddy không phù hợp. Dường như với tôi không có lí do gì mà anh ta không thể chỉ viết lớp của mình, nhắm vào cùng một gói mà anh ta muốn xây dựng một lớp mới bằng cách sử dụng những phương pháp đó, và chỉ làm cho lớp mới của anh ấy gọi họ. Sau đó, ông có thể xây dựng một nhà xây dựng trong lớp học mới của mình và làm tất cả các loại điều thú vị. Mục đích của một codegen nên linh hoạt nếu bạn cần thay đổi một lớp, nhưng nó không nên bị giới hạn quá nhiều nên nó không thể làm điều java mặc định. – Xype

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