| Код | package com.test;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays;
public class Main {
@MyAnnotation(value = "test", zz = {void.class, int.class}, ii=1) String field; public static void main(String[] args) throws Exception { TransformClassLoader tcl = TransformClassLoader.createTransformLoader(); AddFieldAnnoClassTransformer tr = new AddFieldAnnoClassTransformer(); tr.addTargetField("targetField", Main.class.getDeclaredFields()[0].getAnnotations()[0]); tcl.addTransformer(Test.class.getName(), tr); Class<?> clazz = tcl.loadClass(Test.class.getName()); System.out.println(clazz); System.out.println(clazz == Test.class); System.out.println(Arrays.toString(Test.class.getDeclaredFields()[0].getAnnotations())); System.out.println(Arrays.toString(clazz.getDeclaredFields()[0].getAnnotations())); } }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) @interface MyAnnotation { String value(); Class<?>[] zz() default {}; int[] ii(); }
class Test { String targetField; }
|
| Код | package com.test;
import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map;
import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter;
interface ClassTransformer extends ClassVisitor { public void setTargetVisitor(ClassVisitor cv); }
public final class TransformClassLoader extends ClassLoader {
public static TransformClassLoader createTransformLoader() { return createTransformLoader(null); }
public static TransformClassLoader createTransformLoader(final ClassLoader source) { ClassLoader parent = source; if (parent == null) { parent = Thread.currentThread().getContextClassLoader(); if (parent == null) { parent = TransformClassLoader.class.getClassLoader(); } } return new TransformClassLoader(parent); }
private Map<String, ClassTransformer> transformers;
private TransformClassLoader(ClassLoader parent) { super(parent); this.transformers = new HashMap<String, ClassTransformer>(); }
@Override protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> c = super.findLoadedClass(name); if (c == null) { ClassTransformer tr = this.transformers.get(name); if (tr == null) { return super.loadClass(name, resolve); } InputStream is = null; try { is = super.getResourceAsStream(name.replace('.', '/') + ".class"); if (is == null) { throw new ClassNotFoundException(name); } ClassReader reader = new ClassReader(is); ClassWriter writer = new ClassWriter(0); tr.setTargetVisitor(writer); reader.accept(tr, 0); byte[] bytecode = writer.toByteArray(); c = super.defineClass(null, bytecode, 0, bytecode.length); } catch (IOException e) { throw new ClassNotFoundException(name, e); } finally { if (is != null) try { is.close(); } catch (Throwable ignore) {} } } if (resolve) { resolveClass(c); } return c; }
public void addTransformer(String className, ClassTransformer transformer) { if (className == null || className.length() == 0) throw new IllegalArgumentException("className"); if (transformer == null) throw new IllegalArgumentException("transformer"); this.transformers.put(className, transformer); } }
|
| Код | package com.test;
import java.lang.annotation.Annotation; import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map;
import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.ClassAdapter; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Type; import org.objectweb.asm.commons.EmptyVisitor;
public class AddFieldAnnoClassTransformer extends ClassAdapter implements ClassTransformer {
private Map<String, Annotation> fieldsTargets;
public AddFieldAnnoClassTransformer() { super(new EmptyVisitor()); this.fieldsTargets = new HashMap<String, Annotation>(); }
@Override public void setTargetVisitor(ClassVisitor cv) { super.cv = cv; }
public void addTargetField(String fieldName, Annotation annotation) { if (fieldName == null || fieldName.length() == 0) throw new IllegalArgumentException("fieldName"); if (annotation == null) throw new IllegalArgumentException("annotation"); this.fieldsTargets.put(fieldName, annotation); }
@Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { final FieldVisitor fv = super.visitField(access, name, desc, signature, value); if (!this.fieldsTargets.containsKey(name)) { return fv; } final Annotation annotation = this.fieldsTargets.get(name); final String annoDesc = Type.getDescriptor(annotation.annotationType()); return new FieldVisitor() {
boolean alreadyAnnotated = false;
@Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { this.alreadyAnnotated |= desc.equals(annoDesc); return fv.visitAnnotation(desc, visible); }
@Override public void visitAttribute(Attribute attr) { fv.visitAttribute(attr); }
@Override public void visitEnd() { if (!this.alreadyAnnotated) { this.copyAnnotation(fv.visitAnnotation(annoDesc, true), annotation); } fv.visitEnd(); }
private void copyAnnotation(AnnotationVisitor av, Annotation anno) { Method[] methods = anno.annotationType().getDeclaredMethods(); for (Method m : methods) { try { Object defaultValue = m.getDefaultValue(); Object o = m.invoke(anno, (Object[]) null); if (defaultValue != null && defaultValue == o) continue; this.visitValue(av, m.getName(), o); } catch (Exception e) { e.printStackTrace(); }
} av.visitEnd(); }
private void copyArray(AnnotationVisitor av, Object array) { for (int i = 0, len = Array.getLength(array); i < len; ++i) { Object o = Array.get(array, i); this.visitValue(av, null, o); } av.visitEnd(); } private void visitValue(AnnotationVisitor av, String name, Object value) { if (value instanceof Class<?>) { av.visit(name, Type.getType((Class<?>) value)); } else if (value instanceof Enum<?>) { Enum<?> e = (Enum<?>) value; av.visitEnum(name, Type.getDescriptor(e.getDeclaringClass()), e.name()); } else if (value instanceof Annotation) { Annotation a = (Annotation) value; copyAnnotation(av.visitAnnotation(name, Type.getDescriptor(a.annotationType())), a); } else if (value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive()) { copyArray(av.visitArray(name), value); } else { av.visit(name, value); } } }; } }
|
Как то так. |