下面列出了org.objectweb.asm.ClassVisitor#visit ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Creates a new ConsumerGenerator.
*
* @param visitor The class visitor that will be visited with the generated Consumer class
* @param name The name of the class to generate
* @param descriptorA The descriptor of the first type parameter (T in Consumer<T>), for example
* "Ljava/lang/String;"
* @param descriptorB The descriptor of the second type parameter (T in Consumer<T>), for
* example "Ljava/lang/String;"
* @param signatureA The signature of the first type parameter, for example
* "Ljava/util/function/Consumer<Ljava/lang/String;>;"
* @param signatureB The signature of the second type parameter, for example
* "Ljava/util/function/Consumer<Ljava/lang/String;>;"
*/
public BiConsumerGenerator(ClassVisitor visitor, String name, String descriptorA, String descriptorB, String signatureA, String signatureB) {
this.visitor = visitor;
this.name = name;
this.descriptorA = descriptorA;
this.descriptorB = descriptorB;
this.signatureA = signatureA;
this.signatureB = signatureB;
if (signatureA == null) {
signatureA = descriptorA;
}
if (signatureB == null) {
signatureB = descriptorB;
}
visitor.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name, "Ljava/lang/Object;Ljava/util/function/BiConsumer<" + signatureA + signatureB + ">;", "java/lang/Object", new String[] {
"java/util/function/BiConsumer" });
}
@Override
public ClassVisitor wrap(TypeDescription typeDescription, ClassVisitor cv, Context context, TypePool typePool,
FieldList<FieldDescription.InDefinedShape> fieldList, MethodList<?> methodList, int i, int i1)
{
// public void visit(int version, int modifiers, String name, String signature, String superName, String[] interfaces) {
cv.visit(ClassFileVersion.JAVA_V9.getMinorMajorVersion(), typeDescription.getModifiers(), typeDescription.getInternalName(), null,
typeDescription.getSuperClass().asErasure().getInternalName(), typeDescription.getInterfaces().asErasures().toInternalNames());
TypeDescription clazz = this.clazz;
String internalName = clazz.getInternalName();
String descriptor = clazz.getDescriptor();
MethodList<InDefinedShape> declaredMethods = clazz.getDeclaredMethods();
int methodsSize = declaredMethods.size();
String implName = GENERATED_PREFIX + "." + clazz.getName();
String internalImplName = GENERATED_PREFIX.replace('.', '/') + "/" + internalName;
String descriptorImplName = "L" + GENERATED_PREFIX.replace('.', '/') + "/" + internalName + ";";
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cv.visitEnd();
return cv;
}
@Test
public void testInstrumentationModernClassFile() throws Exception {
ClassVisitor classVisitor = TypeConstantAdjustment.INSTANCE.wrap(mock(TypeDescription.class),
this.classVisitor,
mock(Implementation.Context.class),
mock(TypePool.class),
new FieldList.Empty<FieldDescription.InDefinedShape>(),
new MethodList.Empty<MethodDescription>(),
IGNORED,
IGNORED);
classVisitor.visit(ClassFileVersion.JAVA_V5.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
assertThat(classVisitor.visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ}), is(methodVisitor));
verify(this.classVisitor).visit(ClassFileVersion.JAVA_V5.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verify(this.classVisitor).visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verifyNoMoreInteractions(this.classVisitor);
verifyZeroInteractions(methodVisitor);
}
@Test
public void testInstrumentationLegacyClassFileObjectType() throws Exception {
ClassVisitor classVisitor = TypeConstantAdjustment.INSTANCE.wrap(mock(TypeDescription.class),
this.classVisitor,
mock(Implementation.Context.class),
mock(TypePool.class),
new FieldList.Empty<FieldDescription.InDefinedShape>(),
new MethodList.Empty<MethodDescription>(),
IGNORED,
IGNORED);
classVisitor.visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
MethodVisitor methodVisitor = classVisitor.visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
assertThat(methodVisitor, not(this.methodVisitor));
methodVisitor.visitLdcInsn(Type.getType(Object.class));
verify(this.classVisitor).visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verify(this.classVisitor).visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verifyNoMoreInteractions(this.classVisitor);
verify(this.methodVisitor).visitLdcInsn(Type.getType(Object.class).getClassName());
verify(this.methodVisitor).visitMethodInsn(Opcodes.INVOKESTATIC,
Type.getType(Class.class).getInternalName(),
"forName",
Type.getType(Class.class.getDeclaredMethod("forName", String.class)).getDescriptor(),
false);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testInstrumentationLegacyClassFileArrayType() throws Exception {
ClassVisitor classVisitor = TypeConstantAdjustment.INSTANCE.wrap(mock(TypeDescription.class),
this.classVisitor,
mock(Implementation.Context.class),
mock(TypePool.class),
new FieldList.Empty<FieldDescription.InDefinedShape>(),
new MethodList.Empty<MethodDescription>(),
IGNORED,
IGNORED);
classVisitor.visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
MethodVisitor methodVisitor = classVisitor.visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
assertThat(methodVisitor, not(this.methodVisitor));
methodVisitor.visitLdcInsn(Type.getType(Object[].class));
verify(this.classVisitor).visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verify(this.classVisitor).visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verifyNoMoreInteractions(this.classVisitor);
verify(this.methodVisitor).visitLdcInsn(Type.getType(Object[].class).getInternalName().replace('/', '.'));
verify(this.methodVisitor).visitMethodInsn(Opcodes.INVOKESTATIC,
Type.getType(Class.class).getInternalName(),
"forName",
Type.getType(Class.class.getDeclaredMethod("forName", String.class)).getDescriptor(),
false);
verifyNoMoreInteractions(this.methodVisitor);
}
@Test
public void testInstrumentationLegacyClassOtherType() throws Exception {
ClassVisitor classVisitor = TypeConstantAdjustment.INSTANCE.wrap(mock(TypeDescription.class),
this.classVisitor,
mock(Implementation.Context.class),
mock(TypePool.class),
new FieldList.Empty<FieldDescription.InDefinedShape>(),
new MethodList.Empty<MethodDescription>(),
IGNORED,
IGNORED);
classVisitor.visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
MethodVisitor methodVisitor = classVisitor.visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
assertThat(methodVisitor, not(this.methodVisitor));
methodVisitor.visitLdcInsn(FOO);
verify(this.classVisitor).visit(ClassFileVersion.JAVA_V4.getMinorMajorVersion(), FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verify(this.classVisitor).visitMethod(FOOBAR, FOO, BAR, QUX, new String[]{BAZ});
verifyNoMoreInteractions(this.classVisitor);
verify(this.methodVisitor).visitLdcInsn(FOO);
verifyNoMoreInteractions(this.methodVisitor);
}
@Override
public Void visitPackage(PackageElement e, ClassVisitor classVisitor) {
classVisitor.visit(
SourceVersionUtils.sourceVersionToClassFileVersion(targetVersion),
Opcodes.ACC_SYNTHETIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE,
e.getQualifiedName().toString().replace('.', '/') + "/package-info",
null,
"java/lang/Object",
new String[0]);
visitAnnotations(e, classVisitor::visitAnnotation);
new InnerClassesTable(descriptorFactory, accessFlagsUtils, e)
.reportInnerClassReferences(classVisitor);
classVisitor.visitEnd();
return null;
}
public void accept(ClassVisitor visitor)
{
String[] ints = interfaces.getInterfaces().stream().map(i -> i.getName()).toArray(String[]::new);
visitor.visit(version, access, name.getName(), null, super_class.getName(), ints);
visitor.visitSource(source, null);
for (Annotation annotation : annotations.getAnnotations())
{
AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true);
annotation.accept(av);
}
for (Field field : fields)
{
FieldVisitor fv = visitor.visitField(field.getAccessFlags(), field.getName(), field.getType().toString(), null, field.getValue());
field.accept(fv);
}
for (Method method : methods)
{
String[] exceptions = method.getExceptions().getExceptions().stream().map(cl -> cl.getName()).toArray(String[]::new);
if (exceptions.length == 0)
{
exceptions = null;
}
MethodVisitor mv = visitor.visitMethod(method.getAccessFlags(), method.getName(), method.getDescriptor().toString(), null, exceptions);
method.accept(mv);
}
visitor.visitEnd();
}
public static void main(String[] args) throws Exception {
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor tracer =
new TraceClassVisitor(cw, new PrintWriter(System.out));
ClassVisitor cv = tracer;
String name = "Nerd";
String generics = null;
String superName = "java/lang/Object";
String[] interfaces = null;
int access = ACC_PUBLIC + ACC_INTERFACE;
int version = V1_5;
cv.visit(version, access, name, generics, superName, interfaces);
int fieldAccess = ACC_PUBLIC + ACC_FINAL + ACC_STATIC;
String shortDescriptor = Type.SHORT_TYPE.getDescriptor();
FieldVisitor hair = cv.visitField(fieldAccess, "hair", shortDescriptor,
null, new Integer(0));
hair.visitEnd();
MethodVisitor playVideoGame =
cv.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "playVideoGame",
"()V", null, null);
// no code to define, just finish it up
playVideoGame.visitEnd();
cv.visitEnd(); // prints if using tracer
byte[] b = cw.toByteArray();
// can define or write to file:
// defineClass(name, b, 0, b.length)
// from findClass() in subclass of ClassLoader
FileOutputStream fos = new FileOutputStream("Nerd.class");
fos.write(b);
fos.close();
}
public static void main(String[] args) throws Exception {
ClassWriter cw = new ClassWriter(0);
TraceClassVisitor tracer =
new TraceClassVisitor(cw, new PrintWriter(System.out));
ClassVisitor cv = tracer;
String name = "Nerd";
String generics = null;
String superName = "java/lang/Object";
String[] interfaces = null;
int access = ACC_PUBLIC + ACC_INTERFACE;
int version = V1_5;
cv.visit(version, access, name, generics, superName, interfaces);
int fieldAccess = ACC_PUBLIC + ACC_FINAL + ACC_STATIC;
String shortDescriptor = Type.SHORT_TYPE.getDescriptor();
FieldVisitor hair = cv.visitField(fieldAccess, "hair", shortDescriptor,
null, new Integer(0));
hair.visitEnd();
MethodVisitor playVideoGame =
cv.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "playVideoGame",
"()V", null, null);
// no code to define, just finish it up
playVideoGame.visitEnd();
cv.visitEnd(); // prints if using tracer
byte[] b = cw.toByteArray();
// can define or write to file:
// defineClass(name, b, 0, b.length)
// from findClass() in subclass of ClassLoader
FileOutputStream fos = new FileOutputStream("Nerd.class");
fos.write(b);
fos.close();
}
/**
* 生成格式如下的代码,其中ServiceInit_xxx由注解生成器生成。
* <pre>
* package com.sankuai.waimai.router.generated;
*
* public class ServiceLoaderInit {
*
* public static void init() {
* ServiceInit_xxx1.init();
* ServiceInit_xxx2.init();
* }
* }
* </pre>
*/
private void generateServiceInitClass(String directory, Set<String> classes) {
if (classes.isEmpty()) {
WMRouterLogger.info(GENERATE_INIT + "skipped, no service found");
return;
}
try {
WMRouterLogger.info(GENERATE_INIT + "start...");
long ms = System.currentTimeMillis();
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM5, writer) {
};
String className = Const.SERVICE_LOADER_INIT.replace('.', '/');
cv.visit(50, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null);
MethodVisitor mv = cv.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
Const.INIT_METHOD, "()V", null, null);
mv.visitCode();
for (String clazz : classes) {
mv.visitMethodInsn(Opcodes.INVOKESTATIC, clazz.replace('.', '/'),
"init",
"()V",
false);
}
mv.visitMaxs(0, 0);
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
cv.visitEnd();
File dest = new File(directory, className + SdkConstants.DOT_CLASS);
dest.getParentFile().mkdirs();
new FileOutputStream(dest).write(writer.toByteArray());
WMRouterLogger.info(GENERATE_INIT + "cost %s ms", System.currentTimeMillis() - ms);
} catch (IOException e) {
WMRouterLogger.fatal(e);
}
}
@Override
public Void visitType(TypeElement e, ClassVisitor visitor) {
if (classVisitorStarted) {
// We'll get inner class references later
return null;
}
TypeMirror superclass = e.getSuperclass();
if (superclass.getKind() == TypeKind.NONE) {
superclass = Objects.requireNonNull(elements.getTypeElement("java.lang.Object")).asType();
}
int classFileVersion = SourceVersionUtils.sourceVersionToClassFileVersion(targetVersion);
visitor.visit(
classFileVersion,
accessFlagsUtils.getAccessFlagsForClassNode(e),
descriptorFactory.getInternalName(e),
signatureFactory.getSignature(e),
descriptorFactory.getInternalName(superclass),
e.getInterfaces().stream()
.map(descriptorFactory::getInternalName)
.toArray(size -> new String[size]));
classVisitorStarted = true;
// Handle nests in Java 11+. See JEP 181 (https://openjdk.java.net/jeps/181) for details.
if (classFileVersion >= Opcodes.V11) {
if (e.getNestingKind().isNested()) {
visitNestHost(e, visitor);
} else {
visitNestMembers(e, visitor);
}
}
visitAnnotations(e, visitor::visitAnnotation);
super.visitType(e, visitor);
InnerClassesTable innerClassesTable =
new InnerClassesTable(descriptorFactory, accessFlagsUtils, e);
if (e.getKind().isClass() || classFileVersion >= Opcodes.V1_8) {
try {
generateBridges(e, visitor, innerClassesTable);
} catch (UnsupportedOperationException | CannotInferException ex) { // NOPMD
// Can't generate bridges in source-only mode
}
}
innerClassesTable.reportInnerClassReferences(visitor);
return null;
}
private static void visitClass(ClassVisitor cv, String name) {
cv.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", null);
}
private void declareClass(ClassVisitor writer) {
writer.visit(V1_6, ACC_PUBLIC + ACC_SUPER, implementationName, null, classExtended, interfacesImplemented);
}
/**
* Creates a new ConsumerGenerator.
*
* @param visitor The class visitor that will be visited with the generated Consumer class
* @param name The name of the class to generate
* @param descriptor The descriptor of the type parameter (T in {@link java.util.function.Consumer}), for example
* "Ljava/lang/String;"
* @param signature The signature of the type parameter, for example
* "Ljava/util/function/Consumer<Ljava/lang/String;>;"
*/
public ConsumerGenerator(ClassVisitor visitor, String name, String descriptor, String signature) {
this.visitor = visitor;
this.name = name;
this.descriptor = descriptor;
this.signature = signature;
visitor.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER, name, "Ljava/lang/Object;Ljava/util/function/Consumer<" + (signature == null ? descriptor : signature)
+ ">;", "java/lang/Object", new String[] { "java/util/function/Consumer" });
}