本文介绍了在使用AspectJ过程遇到的BCException问题的解决思路,以及如何使用ASM移除Class上的注解。
《断句》
近水楼台先得月,向阳花木易为春。
-宋代,苏麟
问题
在将工程迁移到AndroidX后,在打集成包时遇到一个AspectJ的相关错误(集成包会开启AspectJ功能),从网上各种搜索没有找到相关问题原因,这里记录下解决过程。1
2
3ABORT
[exec] org.aspectj.weaver.BCException: malformed org.aspectj.weaver.EffectiveSignature attribute (length:29)org.aspectj.weaver.BCException: Bad type signature Exceptions
[exec] when batch building with classpath: /opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/cldrdata.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/dnsns.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/jaccess.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/jfxrt.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/localedata.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/nashorn.jar:/opt/soft/jdk/jdk1.8.0_66/jre/lib/ext/sunec.jar:..........
解决方案
起初怀疑是AndroidX的Jetifier功能导致,不了解Jetifier功能的可以看下这篇文章58同城迁移到AndroidX实践及Jetifier源码分析,因为这个版本刚上了AndroidX的需求,但如果真是Jetifier引起的,也只能硬着头皮想办法解决,不可能把AndroidX需求回退的。
从报错信息根本找不到头绪,然后就把工程添加的Aspect相关的注解全部删除了,结果可以成功打包,说明可能是由于注解信息导致的问题,然后再一个一个去还原,然后再打包,最终定位到了是WubaRNSDK中的问题,WubaRNSDK使用了AspectJ对原生react native中发生的异常进行了捕获以及一些其他功能,提供的SDK中已经完成了插桩处理,但AspectJ的注解还保留着,最终在WubaRNSDK完成插桩处理后通过asm把相关注解给移除后终于可以正常打包。
使用ASM移除指定注解
使用JarFile遍历jar包,使用ASM对class文件进行处理:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27JarFile file = new JarFile(aspectedClassesJarFile.absolutePath)
File temp = new File(project.buildDir.getPath() + "/wubarn/temp.jar")
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(temp))
Enumeration<JarEntry> entries = file.entries()
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
ZipEntry zipEntry = new ZipEntry(jarEntry.getName());
InputStream inputStream = file.getInputStream(jarEntry);
byte[] bytes = toByteArray(inputStream);
if (jarEntry.getName().endsWith(".class")) {
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, 0);
ClassVisitor classVisitor = new RemoveClassVisitor(Opcodes.ASM4,writer);
reader.accept(classVisitor, 0);
bytes = writer.toByteArray();
}
inputStream.close();
jarOutputStream.putNextEntry(zipEntry);
jarOutputStream.write(bytes);
jarOutputStream.closeEntry();
}
file.close();
jarOutputStream.close();
aspectedClassesJarFile.delete()
temp.renameTo(new File(project.buildDir.getPath() + "/wubarn/classes.jar"))
自定义类继承ClassVisitor重写visitAnnotation方法,判断为指定注解时返回null即可移除类上的相关注解:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class RemoveClassVisitor extends ClassVisitor{
...
@Override
AnnotationVisitor visitAnnotation(String s, boolean b) {
if (s.equals("Lorg/aspectj/lang/annotation/Aspect;")) {
return null;
}
return super.visitAnnotation(s, b)
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
return new RemoveMethodVisitor(Opcodes.ASM4,super.visitMethod(access, name, desc, signature, exceptions));
}
}
自定义类继承MethodVisitor重写visitAnnotation方法,在判断是指定注解后返回null即可移除方法上的相关注解:1
2
3
4
5
6
7
8
9
10
11class RemoveMethodVisitor extends MethodVisitor{
...
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (desc.equals("Lorg/aspectj/lang/annotation/Around;")) {
return null;
}
return super.visitAnnotation(desc, visible);
}
}
总结
在使用AspectJ的过程中可能会遇到没有足够提示信息的错误,这里我们通过排除尝试法最终解决该问题,希望能给大家带来一些启示。