Cách gọi một private method trong Java với Reflecion

Trong khi các private method được tạo ra nhằm ngăn chặn việc chúng bị gọi thực thi từ phía bên ngoài class, tuy nhiên nếu chúng ta muốn làm điều này vì một số lý do nào đó thì vẫn có một số cách để làm được.

Trong Java, cách truyền thống để gọi một private method là dùng Java Reflection, tuy nhiên cũng có một số thư viện bên ngoài hỗ trợ chúng ta làm việc này nhưng hãy lưu ý là bên dưới chúng cơ bản vẫn là Java Reflection.

Chuẩn bị

Giả sử chúng ta có một LongArrayUtil class chứa các private method như sau

public class LongArrayUtil {

    public static int indexOf(long[] array, long target) {
        return indexOf(array, target, 0, array.length);
    }

    private static int indexOf(long[] array, long target, int start, int end) {
        for (int i = start; i < end; i++) {
            if (array[i] == target) {
                return i;
            }
        }
        return -1;
    }
}

Đặt trường hợp chúng ta đang có nhu cầu sử dụng indexOf() method bên trong LongArrayUtil class nhưng không được chỉnh sửa các method này từ private sang public. Do đó sau đây chúng ta sẽ thử dùng Java Reflection để làm việc này xem như thế nào.

Java Reflection API

Trong khi các trình biên dịch Java ngăn chặn chúng ta gọi các private method thông qua việc viết mã tường minh thì chúng ta có thế sử dụng Java Reflection để làm điều này. Để gọi một private method tất cả những gì chúng ta cần làm là thông qua một Method instance được cung cấp từ gói java reflection.

Method indexOfMethod = LongArrayUtil.class.getDeclaredMethod(
  "indexOf", long[].class, long.class, int.class, int.class);

Như đoạn code trên chúng ta đang cố gắng lấy một method trong LongArrayUtil có tên là indexOf, với các tham số đầu vào lần lượt là long[], long, int, int. Có nghĩa là chúng ta đang hướng đến method này

private static int indexOf(long[] array, long target, int start, int end) {
    for (int i = start; i < end; i++) {
        if (array[i] == target) {
            return i;
        }
    }
    return -1;
}

Tiếp theo chúng ta cần thực hiện một thao tác đơn giản cho phép bên ngoài truy cập vào indexOf() method thông qua

indexOfMethod.setAccessible(true);

Và cuối cùng chúng ta có đoạn code hoàn chỉnh như sau, sử dụng invoke() method để gọi private method trong LongArrayUtil class.

public class Main {

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method indexOfMethod = LongArrayUtil.class.getDeclaredMethod(
                "indexOf", long[].class, long.class, int.class, int.class);

        indexOfMethod.setAccessible(true);

        long[] arr = {1L, 45L, 89L};
        int value = (int) indexOfMethod.invoke(
                LongArrayUtil.class, arr, 45L, 0, arr.length);

        System.out.println("Index: " + value);
    }
}

Output: Index: 1

Spring ReflectionTestUtils

Việc gọi các private method của một class trong unit-test là một việc diễn ra rất thường xuyên. Do đó nếu dự án của bạn đang sử dụng Spring framework thì nó đã cung cấp sẵn ReflectionTestUtils cho phép gọi một private method mà không cần phải tốn quá nhiều công sức.

Đầu tiên chúng ta cần phải thêm spring-test dependency vào spring project

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.4</version>
    <scope>test</scope>
</dependency>

Sau đó chúng ta có thể sử dụng ReflectionTestUtils một cách đơn giản với invokeMethod() method được cung cấp sẵn.

int value = ReflectionTestUtils.invokeMethod(
  LongArrayUtil.class, "indexOf", someLongArray, 1L, 1, someLongArray.length);

Tóm lược

Như vậy là chúng ta đã biết cách gọi một private method thông qua Java Reflection và các thư viện utils. Nhưng các bạn cần lưu ý rằng Reflection không được khuyến khích sử dụng nếu không thật sự có nhu cầu vì rất khó để bảo trì các đoạn code này. 

Hãy cân nhắc các cách thay thế chẳng hạn như nếu bạn có thể chỉnh sửa mã code được thì nên dùng thay vì dùng Reflection v.v

Nguồn: Baeldung

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x