2011-12-18 42 views
5

gọi Hãy nói rằng tôi có một tình huống như thế này:Xem chú thích java trên phương pháp

public String method(String s) { 
    return stringForThisVisibility(s, EnumVisibility.PUBLIC); 
} 

và tôi muốn thay thế nó với một chú thích như thế này:

@VisibilityLevel(value = EnumVisibility.PUBLIC) 
public String method(String s) { 
    return stringForThisVisibility(s); 
} 

này có vẻ là một tốt hơn và giải pháp rõ ràng hơn, nhưng tôi cần phương thức stringForThisVisibility để biết giá trị của @VisibilityLevel với một số loại phản ánh. Điều đó có thể không? Tôi có thể xem các chú thích trên phương thức gọi stringForThisVisibility không?

Trả lời

5

Bạn cần có đối tượng Method đại diện cho phương pháp được gọi là stringForThisVisibility. Thật không may, Java không cung cấp chức năng này ra khỏi hộp.

Tuy nhiên, chúng tôi vẫn có thể nhận được Method thông qua thông tin được trả lại bởi Thread.currentThread().getStackTrace(). Phương thức đó trả về một mảng các đối tượng StackTraceElement. Mỗi đối tượng StackTraceElement cho chúng ta ba điều:

Có thể mất một số thử nghiệm, nhưng bạn nên tìm chỉ mục nào trong mảng đó đại diện cho phương pháp bạn quan tâm (nó wil l có lẽ là đầu tiên, thứ hai hoặc thứ ba StackTraceElement trong mảng).

Khi bạn có mong muốn StackTraceElement, bạn có thể nhận đối tượng Method tương ứng bằng cách sử dụng kỹ thuật trong my answer cho câu hỏi có tiêu đề "Get caller's method (java.lang.reflect.Method)". Kỹ thuật đó sẽ vẫn là từ, ngay cả khi lớp có nhiều phương thức với tên phương thức đó. Có những kỹ thuật đơn giản hơn nếu bạn không lo lắng về kịch bản đó.

Khi bạn có đối tượng Method, đó chỉ là vấn đề gọi method.getAnnotation(VisibilityLevel.class).

6

có bạn có thể. nội dung nào đó dọc theo các dòng của

StackTraceElement[] stack = Thread.currentThread().getStackTrace(); 
Class callerClass = Class.forName(stack[stack.length-2].getClassName()); 
callerClass.isAnnotationPresent(...) 

mã ở trên sẽ tìm chú thích trên lớp. bạn có thể kết hợp tên lớp và tên phương thức (cũng từ phần tử stack trace) và xem xét phương thức. lưu ý rằng điều này cực kỳ chậm.

+2

Đó là giải pháp duy nhất tôi biết. Không phải là nó không được bảo đảm làm việc trong mọi tình huống: Nếu trình nạp lớp nạp lớp được gọi không biết lớp gọi (và không có trình nạp lớp cha nào của nó làm), lệnh gọi tới 'Class.forName()' sẽ thất bại. –

+0

Vì vậy, bạn nói rằng có thể tốt hơn để được hài lòng với giải pháp đầu tiên ... – Fabio

+1

kỹ thuật này là mong manh (nếu phương pháp của bạn không được gọi trực tiếp từ một phương thức chú thích? Bạn cần phải lặp qua ngăn xếp. là trên một phương thức superclass và không phải trên phương thức gọi trực tiếp? bạn cần phải lặp qua superclasses ...) và nếu Philipp là đúng, nó có thể làm hỏng các môi trường phức tạp (j2ee? osgi?). nó cũng rất chậm. bạn có thể chọn giải pháp sử dụng điểm đánh dấu ThreadLocal và đặt điểm đánh dấu trước khi gọi phương thức, nhưng điều đó cũng sẽ trông kỳ lạ. có lẽ nếu bạn có thể mô tả chính xác những gì bạn đang cố gắng để làm một giải pháp thanh lịch có thể được tìm thấy – radai

8

Với lớp sau:

/** 
    * Proper use of this class is 
    *  String testName = (new Util.MethodNameHelper(){}).getName(); 
    * or 
    *  Method me = (new Util.MethodNameHelper(){}).getMethod(); 
    * the anonymous class allows easy access to the method name of the enclosing scope. 
    */ 
    public static class MethodNameHelper { 
    public String getName() { 
     final Method myMethod = this.getClass().getEnclosingMethod(); 
     if (null == myMethod) { 
     // This happens when we are non-anonymously instantiated 
     return this.getClass().getSimpleName() + ".unknown()"; // return a less useful string 
     } 
     final String className = myMethod.getDeclaringClass().getSimpleName(); 
     return className + "." + myMethod.getName() + "()"; 
    } 

    public Method getMethod() { 
     return this.getClass().getEnclosingMethod(); 
    } 
    } 

Người ta có thể gọi:. Phương pháp tôi = (Util.MethodNameHelper mới() {}) GetMethod();

Tôi sử dụng rộng rãi lệnh gọi getName() trong lớp đó. Trên máy tính của tôi, các instantiation class ẩn danh cộng với các lời gọi phương thức có xu hướng tốn khoảng 1500 ns mỗi. Phương pháp tiếp cận đi bộ StackElement tốn khoảng 30 lần (47000 ns) trên máy tính của tôi trong thử nghiệm hiệu suất của tôi.

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