2012-05-17 19 views
14

Tôi muốn cung cấp chú thích với một số giá trị được tạo bởi một số phương pháp.Giá trị chú thích Java được cung cấp theo cách năng động

Tôi cố gắng này cho đến nay:

public @interface MyInterface { 
    String aString(); 
} 

@MyInterface(aString = MyClass.GENERIC_GENERATED_NAME) 
public class MyClass { 

    static final String GENERIC_GENERATED_NAME = MyClass.generateName(MyClass.class); 

    public static final String generateName(final Class<?> c) { 
     return c.getClass().getName(); 
    } 
} 

tưởng GENERIC_GENERATED_NAMEstatic final là, nó than phiền rằng

Giá trị cho chú thích thuộc tính MyInterface.aString phải là một biểu thức hằng

Vậy làm thế nào để đạt được điều này?

Trả lời

14

Không có cách nào để tự động tạo chuỗi được sử dụng trong chú thích. Trình biên dịch đánh giá siêu dữ liệu chú thích cho các chú thích RetentionPolicy.RUNTIME tại thời gian biên dịch, nhưng GENERIC_GENERATED_NAME không được biết cho đến khi chạy. Và bạn không thể sử dụng các giá trị được tạo cho các chú thích là RetentionPolicy.SOURCE vì chúng bị loại bỏ sau thời gian biên dịch, vì vậy các giá trị được tạo sẽ không bao giờ được biết là.

+0

Ok, vì vậy tôi hiểu rằng điều này không thể được giải quyết bằng cách sử dụng chú thích, phải không? Có lẽ sau đó tôi sẽ phải chạy một số công cụ trước khi biên dịch và hoàn thành nguồn Java. Bất kỳ đề xuất nào khác? – thelost

+0

@thelost Tôi chưa bao giờ nhìn vào tất cả những gì phải thành thật. Hãy để tôi nhìn xung quanh một chút trong thời gian rảnh của tôi hôm nay và tôi sẽ cố gắng để lấy lại cho bạn vào nó. –

4

Giải pháp là sử dụng phương pháp được chú thích thay thế. Gọi phương thức đó (với sự phản chiếu) để nhận giá trị động.

Từ quan điểm của người sử dụng chúng ta sẽ có:

@MyInterface 
public class MyClass { 
    @MyName 
    public String generateName() { 
     return MyClass.class.getName(); 
    } 
} 

Chú thích riêng của mình sẽ được định nghĩa là

@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
public @interface @MyName { 
} 

Thực hiện tra cứu cho cả hai người các chú thích này là khá thẳng về phía trước.

// as looked up by @MyInterface 
Class<?> clazz; 

Method[] methods = clazz.getDeclaredMethods(); 
if (methods.length != 1) { 
    // error 
} 
Method method = methods[0]; 
if (!method.isAnnotationPresent(MyName.class)) { 
    // error as well 
} 
// This works if the class has a public empty constructor 
// (otherwise, get constructor & use setAccessible(true)) 
Object instance = clazz.newInstance(); 
// the dynamic value is here: 
String name = (String) method.invoke(instance); 
+0

Trong trường hợp của bạn, thậm chí có thể sử dụng một phương pháp tĩnh. Để gọi nó qua phản ánh, hãy xem http://stackoverflow.com/a/2467562/1068385 – Arvidaa

0

Không có cách nào để sửa đổi thuộc tính của chú thích động như người khác nói. Tuy nhiên nếu bạn muốn đạt được điều đó, có hai cách để làm điều này.

  1. Chỉ định biểu thức cho thuộc tính trong chú thích và xử lý biểu thức đó bất cứ khi nào bạn truy xuất chú thích. Trong trường hợp của bạn chú thích của bạn có thể

    @MyInterface (aString = "objectA.doSomething (args1, args2)")

Khi bạn đọc, bạn có thể xử lý chuỗi và thực hiện những phương pháp gọi và lấy giá trị. Spring làm điều đó bằng SPEL (ngôn ngữ biểu hiện Spring). Đây là tài nguyên chuyên sâu và các chu kỳ CPU được lãng phí mỗi khi chúng ta muốn xử lý biểu thức. Nếu bạn đang sử dụng spring, bạn có thể hook trong beanPostProcessor và xử lý biểu thức một lần và lưu trữ kết quả ở đâu đó. (Một đối tượng thuộc tính toàn cầu hoặc trong một bản đồ có thể được lấy ra ở bất kỳ đâu).

  1. Đây là cách hacky để làm những gì chúng tôi muốn. Java lưu trữ một biến riêng để duy trì một bản đồ các chú thích trên lớp/trường/phương thức. Bạn có thể sử dụng sự phản chiếu và giữ lấy bản đồ đó. Vì vậy, trong khi xử lý chú thích lần đầu tiên, chúng tôi giải quyết biểu thức và tìm giá trị thực tế. Sau đó, chúng ta tạo một đối tượng chú thích của kiểu được yêu cầu.Chúng tôi có thể đặt chú thích mới được tạo với giá trị thực tế (liên tục) vào thuộc tính của chú thích và ghi đè chú thích thực tế trong bản đồ đã truy xuất.

Cách jdk lưu trữ bản đồ chú thích là phụ thuộc phiên bản java và không đáng tin cậy vì nó không được sử dụng (nó là riêng tư).

Bạn có thể tìm thấy triển khai tham chiếu tại đây.

https://rationaleemotions.wordpress.com/2016/05/27/changing-annotation-values-at-runtime/

Tái bút: Tôi đã không cố gắng và thử nghiệm các phương pháp thứ hai.

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