下面列出了org.objectweb.asm.ClassVisitor#visitEnd ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
public Class<?> translate(Plugin plugin) throws IOException {
// 防止出现 Class not found 的奇葩问题,使用缓存(目的是兼容热重载)
InputStream inputStream = useCache ? new ByteArrayInputStream(cacheClasses.computeIfAbsent(target, n -> {
try {
return IO.readFully(Files.getResource(plugin, target.replace(".", "/") + ".class"));
} catch (IOException e) {
e.printStackTrace();
}
return new byte[0];
})) : Files.getResource(plugin, target.replace(".", "/") + ".class");
// 读取
ClassReader classReader = new ClassReader(inputStream);
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor classVisitor = new SimpleClassVisitor(this, classWriter);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
classWriter.visitEnd();
classVisitor.visitEnd();
// 打印
if (mapping || plugin instanceof InternalPlugin) {
executorService.submit(this::printMapping);
}
// 因第三方插件调用该方法时会出现找不到类,所以第三方插件使用 BridgeLoader 加载类
return plugin instanceof InternalPlugin ? AsmClassLoader.createNewClass(target, classWriter.toByteArray()) : BridgeLoader.createNewClass(target, classWriter.toByteArray());
}
public Class<?> translateBridge() throws IOException {
Class<?> callerClass = Ref.getCallerClass(3).orElse(null);
if (callerClass != null && !callerClass.getName().startsWith("io.izzel")) {
throw new IllegalStateException();
}
ClassReader classReader = new ClassReader(Files.getTabooLibResource(target.replace(".", "/") + ".class"));
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor classVisitor = new SimpleClassVisitor(this, classWriter);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
classWriter.visitEnd();
classVisitor.visitEnd();
if (mapping || plugin instanceof InternalPlugin) {
executorService.submit(this::printMapping);
}
return BridgeLoader.createNewClass(target, classWriter.toByteArray());
}
public static void inject(Plugin plugin, Class<?> clazz) {
if (clazz.equals(TabooLib.class)) {
for (Dependency dependency : TabooLib.class.getAnnotationsByType(Dependency.class)) {
for (String url : dependency.url().split(";")) {
try {
if (TDependency.requestLib(dependency.maven(), dependency.mavenRepo(), url)) {
break;
}
} catch (Throwable ignored) {
}
}
}
} else {
try {
ClassReader classReader = new ClassReader(Files.getResource(plugin, clazz.getName().replace(".", "/") + ".class"));
ClassWriter classWriter = new ClassWriter(0);
ClassVisitor classVisitor = new DependencyClassVisitor(plugin, classWriter);
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
classWriter.visitEnd();
classVisitor.visitEnd();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
@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;
}
@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);
}
}
public void driveVisitor(Element fullElement, ClassVisitor visitor) {
fullElement.accept(new ElementVisitorAdapter(), visitor);
visitor.visitEnd();
}