如何使用 Java 推断自定义注释中的信息
How to Infer Information in Custom Annotation with Java
我创建了一个名为 CrudSearchable 的自定义注释,并在那里定义了一些属性。但是,我正在分配的属性已经从 bean 中可见。有没有一种方法可以获取这些值而无需手动重新定义它们?
// Bean
public class MockUser {
@CrudSearchable(attribute = "name",
parentClass = MockUser.class)
private String name;
@CrudSearchable(attribute = "group",
parentClass = MockUser.class,
mappedClass = MockGroup.class)
private MockGroup group;
// Get/Set, Equals/Hashcode, etc...
}
// Annotation Class
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CrudSearchable {
String attribute();
boolean searchable() default true;
Class<?> mappedClass() default CrudSearchable.class;
Class<?> parentClass() default Object.class;
}
其中 attribute 是属性名称,parentClass 是使用注释的 class 文字,mapped class 是嵌套的 class 对象(如果适用)。
MockUser obj = new MockUser();
Class<?> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
CrudSearchable annotation = fields[0].getAnnotation(CrudSearchable.class);
System.out.println("attribute: " + annotation.attribute() +
"searchable: " + annotation.searchable());
希望对您有所帮助
我在另一个问题上找到了答案。这就是我要找的。
// Put in Reflector.java
/**
* Changes the annotation value for the given key of the given annotation to newValue and returns
* the previous value.
*/
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key,newValue);
return oldValue;
}
一旦我有了这个,我就可以在构造函数中调用下面的方法来改变我使用的注释。
// Put in Service Class
public void modifySearchable(Class<?> clazz) {
for(Field f : clazz.getDeclaredFields()){
CrudSearchable[] searchableArray = f.getDeclaredAnnotationsByType(CrudSearchable.class);
for(CrudSearchable searchable : searchableArray){
if(searchable == null){
continue;
}
Reflector.alterAnnotation(searchable, "attribute", f.getName());
Reflector.alterAnnotation(searchable, "parentClass", clazz);
if(!(searchable.mappedAttribute().equals(""))){
String mappedGetter = "get" +
searchable.mappedAttribute().substring(0, 1).toUpperCase() +
searchable.mappedAttribute().substring(1);
Reflector.alterAnnotation(searchable, "mappedClass", f.getType());
Reflector.alterAnnotation(searchable, "mappedGetter", mappedGetter);
}
}
}
}
// Changed Bean
@Id
@GeneratedValue
@Column(name = "MOCK_USER_ID")
private Long id;
@Column(name = "MOCK_USER_NAME")
@CrudSearchable
private String name;
@ManyToOne
@JoinColumn(name = "MOCK_GROUP", nullable = false)
@CrudSearchable(mappedAttribute = "name")
private MockGroup group;
public MockUser(){
super();
new Searchable<>().modifySearchable(this.getClass());
}
更改值而不是让用户定义它们似乎很多,但我相信这将使代码更加用户友好。
希望这对某人有所帮助。我在 post: Modify a class definition's annotation string parameter at runtime 上找到了答案。看看吧!
我创建了一个名为 CrudSearchable 的自定义注释,并在那里定义了一些属性。但是,我正在分配的属性已经从 bean 中可见。有没有一种方法可以获取这些值而无需手动重新定义它们?
// Bean
public class MockUser {
@CrudSearchable(attribute = "name",
parentClass = MockUser.class)
private String name;
@CrudSearchable(attribute = "group",
parentClass = MockUser.class,
mappedClass = MockGroup.class)
private MockGroup group;
// Get/Set, Equals/Hashcode, etc...
}
// Annotation Class
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface CrudSearchable {
String attribute();
boolean searchable() default true;
Class<?> mappedClass() default CrudSearchable.class;
Class<?> parentClass() default Object.class;
}
其中 attribute 是属性名称,parentClass 是使用注释的 class 文字,mapped class 是嵌套的 class 对象(如果适用)。
MockUser obj = new MockUser();
Class<?> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
CrudSearchable annotation = fields[0].getAnnotation(CrudSearchable.class);
System.out.println("attribute: " + annotation.attribute() +
"searchable: " + annotation.searchable());
希望对您有所帮助
我在另一个问题上找到了答案。这就是我要找的。
// Put in Reflector.java
/**
* Changes the annotation value for the given key of the given annotation to newValue and returns
* the previous value.
*/
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key,newValue);
return oldValue;
}
一旦我有了这个,我就可以在构造函数中调用下面的方法来改变我使用的注释。
// Put in Service Class
public void modifySearchable(Class<?> clazz) {
for(Field f : clazz.getDeclaredFields()){
CrudSearchable[] searchableArray = f.getDeclaredAnnotationsByType(CrudSearchable.class);
for(CrudSearchable searchable : searchableArray){
if(searchable == null){
continue;
}
Reflector.alterAnnotation(searchable, "attribute", f.getName());
Reflector.alterAnnotation(searchable, "parentClass", clazz);
if(!(searchable.mappedAttribute().equals(""))){
String mappedGetter = "get" +
searchable.mappedAttribute().substring(0, 1).toUpperCase() +
searchable.mappedAttribute().substring(1);
Reflector.alterAnnotation(searchable, "mappedClass", f.getType());
Reflector.alterAnnotation(searchable, "mappedGetter", mappedGetter);
}
}
}
}
// Changed Bean
@Id
@GeneratedValue
@Column(name = "MOCK_USER_ID")
private Long id;
@Column(name = "MOCK_USER_NAME")
@CrudSearchable
private String name;
@ManyToOne
@JoinColumn(name = "MOCK_GROUP", nullable = false)
@CrudSearchable(mappedAttribute = "name")
private MockGroup group;
public MockUser(){
super();
new Searchable<>().modifySearchable(this.getClass());
}
更改值而不是让用户定义它们似乎很多,但我相信这将使代码更加用户友好。
希望这对某人有所帮助。我在 post: Modify a class definition's annotation string parameter at runtime 上找到了答案。看看吧!