sun.reflect.annotation.AnnotationParser#annotationForMap
/**
* Returns an annotation of the given type backed by the given
* member -> value map.
*/
public static Annotation annotationForMap(final Class<? extends Annotation> type,
final Map<String, Object> memberValues)
{
return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
public Annotation run() {
return (Annotation) Proxy.newProxyInstance(
type.getClassLoader(), new Class<?>[] { type },
new AnnotationInvocationHandler(type, memberValues));
}});
}
此方法可以根据type
和memberValues
两个入参生成一个对应的注解实例,可以近似理解成使用反射技术生成一个类的实例。可以看到,他的返回值是一个很熟悉的方法,没错,就是JDK动态代理中用于实现切面逻辑的方法java.lang.reflect.Proxy#newProxyInstance
。那么就好办了,我们只需要看懂new AnnotationInvocationHandler(type, memberValues)
这个类就行了。下面是这个类的主要代码:
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
private final Class<? extends Annotation> type;
private final Map<String, Object> memberValues;
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
Class<?>[] superInterfaces = type.getInterfaces();
if (!type.isAnnotation() ||
superInterfaces.length != 1 ||
superInterfaces[0] != java.lang.annotation.Annotation.class)
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
this.type = type;
this.memberValues = memberValues;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String member = method.getName();
Class<?>[] paramTypes = method.getParameterTypes();
// Handle Object and Annotation methods
if (member.equals("equals") && paramTypes.length == 1 &&
paramTypes[0] == Object.class)
return equalsImpl(args[0]);
if (paramTypes.length != 0)
throw new AssertionError("Too many parameters for an annotation method");
switch(member) {
case "toString":
return toStringImpl();
case "hashCode":
return hashCodeImpl();
case "annotationType":
return type;
}
// Handle annotation member accessors
Object result = memberValues.get(member);
if (result == null)
throw new IncompleteAnnotationException(type, member);
if (result instanceof ExceptionProxy)
throw ((ExceptionProxy) result).generateException();
if (result.getClass().isArray() && Array.getLength(result) != 0)
result = cloneArray(result);
return result;
}
...
}
invoke
方法中,member
是方法名,memberValues
是传入的键值对,意思就是,只要传入注解的类,和类中方法名对应的值,就可以生成一个注解
编写如下代码进行测试:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface AnnoProxyTest
{
String value();
}
private void testAnnotationForMap() {
Map<String, Object> map = new HashMap<>();
map.put("value", "hello");
Annotation annotation = AnnotationParser.annotationForMap(AnnoProxyTest.class, map);
System.err.println(annotation);
System.err.println(annotation instanceof AnnoProxyTest);
AnnoProxyTest annoProxyTest = (AnnoProxyTest) annotation;
System.err.println(annoProxyTest.value());
}
// 输出:
// > @com.xml.demo.basicknowledge.proxy.anno.AnnoProxy$AnnoProxyTest(value=hello)
// > true
// > hello
看结果就是生成了一个正常的注解。
再搞点骚操作,写一个半成的
private void testCreateAnnotation() {
Class<? extends Annotation> type = AnnoProxyTest.class;
Map<String, Object> memberValues = new HashMap<>();
memberValues.put("value", "1");
Annotation annotation = (Annotation) Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[] {type},
(proxy, method, args) -> memberValues.get(method.getName()));
System.err.println(annotation);
System.err.println(annotation instanceof AnnoProxyTest);
AnnoProxyTest annoProxyTest = (AnnoProxyTest) annotation;
System.err.println(annoProxyTest.value());
}
// 输出:
// > null
// > true
// > 1
也是可以正常输出的,只不过没有实现toString
方法,所以输出为null,但是调用其中方法还是可以正常输出的,且类型也是正确的
总结:注解就是一个JDK代理类
AccessController.doPrivileged
AccessController.doPrivileged - 山河已无恙 - 博客园 (cnblogs.com)
标签:memberValues,AnnoProxyTest,annotationForMap,实例,result,new,注解,type,annotation From: https://www.cnblogs.com/xmlxml/p/18003286