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?
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
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ụ. –
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