我们使用的是包含被注解为JAXB注释豆库。 没有在我们使用这些类的方式取决于JAXB。 换句话说,我们并不需要JAXB,不依赖于注解。
然而,由于存在注解,他们最终通过这一过程注解其他类被引用。 这要求我捆绑JAXB在我们的应用程序,这是不允许的,因为JAXB是在javax.*
包(机器人不允许“核心库”将包含在你的应用程序)。
因此,考虑到这一点,我正在寻找一种方式来从编译后的字节代码中删除注释。 我知道有操纵字节码的实用程序,但是这是一个相当新的给我。 任何帮助入门朝着为此,将不胜感激。
我建议BCEL 6.您还可以使用ASM,但我听说BCEL更容易使用。 下面是制备场最后一个快速测试方法:
public static void main(String[] args) throws Exception {
System.out.println(F.class.getField("a").getModifiers());
JavaClass aClass = Repository.lookupClass(F.class);
ClassGen aGen = new ClassGen(aClass);
for (Field field : aGen.getFields()) {
if (field.getName().equals("a")) {
int mods = field.getModifiers();
field.setModifiers(mods | Modifier.FINAL);
}
}
final byte[] classBytes = aGen.getJavaClass().getBytes();
ClassLoader cl = new ClassLoader(null) {
@Override
protected synchronized Class<?> findClass(String name) throws ClassNotFoundException {
return defineClass("F", classBytes, 0, classBytes.length);
}
};
Class<?> fWithoutDeprecated = cl.loadClass("F");
System.out.println(fWithoutDeprecated.getField("a").getModifiers());
}
当然,你实际上写你的类到磁盘上的文件,然后罐子起来,但是这是一个尝试新事物变得轻松。 我没有BCEL 6得心应手,所以我不能修改这个例子删除注释,但我想象中的代码会是这样的:
public static void main(String[] args) throws Exception {
...
ClassGen aGen = new ClassGen(aClass);
aGen.setAttributes(cleanupAttributes(aGen.getAttributes()));
aGen.getFields();
for (Field field : aGen.getFields()) {
field.setAttributes(cleanupAttributes(field.getAttributes()));
}
for (Method method : aGen.getMethods()) {
method.setAttributes(cleanupAttributes(method.getAttributes()));
}
...
}
private Attribute[] cleanupAttributes(Attribute[] attributes) {
for (Attribute attribute : attributes) {
if (attribute instanceof Annotations) {
Annotations annotations = (Annotations) attribute;
if (annotations.isRuntimeVisible()) {
AnnotationEntry[] entries = annotations.getAnnotationEntries();
List<AnnotationEntry> newEntries = new ArrayList<AnnotationEntry>();
for (AnnotationEntry entry : entries) {
if (!entry.getAnnotationType().startsWith("javax")) {
newEntries.add(entry);
}
}
annotations.setAnnotationTable(newEntries);
}
}
}
return attributes;
}
ProGuard的也将做到这一点,除了混淆你的代码。
另外还有一个AntTask 清除注解参考Ant任务 ,这
吹扫到注解引用了Java字节码/类文件的(删除注释元素@Anno标记)。 现在,您可以使用标注来检查字节码编译星座后,但释放的罐子之前删除旧annos。
我已经使用ByteBuddy库中删除注释。 不幸的是我无法删除与高层API注解,所以我用ASM API。 下面是例子,如何从一个类的字段中删除@Deprecated注释:
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.asm.AsmVisitorWrapper;
import net.bytebuddy.description.field.FieldDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.jar.asm.AnnotationVisitor;
import net.bytebuddy.jar.asm.FieldVisitor;
import net.bytebuddy.jar.asm.Opcodes;
import net.bytebuddy.jar.asm.Type;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.annotation.Annotation;
import java.util.Arrays;
public class Test {
public static class Foo {
@Deprecated
public Integer bar;
}
public static void main(String[] args) throws Exception {
System.out.println("Annotations before processing " + getAnnotationsString(Foo.class));
Class<? extends Foo> modifiedClass = new ByteBuddy()
.redefine(Foo.class)
.visit(new AsmVisitorWrapper.ForDeclaredFields()
.field(ElementMatchers.isAnnotatedWith(Deprecated.class),
new AsmVisitorWrapper.ForDeclaredFields.FieldVisitorWrapper() {
@Override
public FieldVisitor wrap(TypeDescription instrumentedType,
FieldDescription.InDefinedShape fieldDescription,
FieldVisitor fieldVisitor) {
return new FieldVisitor(Opcodes.ASM5, fieldVisitor) {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (Type.getDescriptor(Deprecated.class).equals(desc)) {
return null;
}
return super.visitAnnotation(desc, visible);
}
};
}
}))
// can't use the same name, because Test$Foo is already loaded
.name("Test$Foo1")
.make()
.load(Test.class.getClassLoader())
.getLoaded();
System.out.println("Annotations after processing " + getAnnotationsString(modifiedClass));
}
private static String getAnnotationsString(Class<? extends Foo> clazz) throws NoSuchFieldException {
Annotation[] annotations = clazz.getDeclaredField("bar").getDeclaredAnnotations();
return Arrays.toString(annotations);
}
}