我们正在使用一个包含用JAXB注释的bean的库。我们使用这些类的方式并不依赖于JAXB。换句话说,我们不需要JAXB,也不依赖于注释。
然而,由于注释的存在,它们最终会被处理注释的其他类引用。这要求我在应用程序中绑定JAXB,这是不允许的,因为JAXB在javax中*
软件包(Android不允许在应用程序中包含“核心库”)。
因此,考虑到这一点,我正在寻找一种从编译的字节码中删除注释的方法。我知道有一些用于操作字节码的实用程序,但这对我来说是相当新鲜的。我该怎么开始?
ProGuard也会这样做,除了混淆你的代码。
我使用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);
}
}
我推荐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());
}
当然,您实际上会将类作为文件写入磁盘,然后将它们放入jar,但这更容易尝试。我手头没有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;
}
问题内容: 我遇到了一些有关JVM / JIT活动的参考,其中似乎在编译字节码和解释字节码之间有区别。该特定注释声明的字节码在前10000次运行时进行解释,然后进行编译。 “编译”和“解释”字节码之间有什么区别? 问题答案: 解释字节码基本上是逐行读取字节码,不进行任何优化或任何操作,然后对其进行解析并实时执行。由于许多原因,这种方法效率低下,其中包括Java字节码设计得不能快速解释的问题。 编译
导航 目录 上一章:Lua 与 C/C++ 交互 下一章:LuaJIT 介绍
问题内容: 我想做一个获取字符串的函数,以防它有内联注释时将其删除。我知道这听起来很简单,但是我想确保即时消息正确执行,例如: 我考虑了两种方法:否则请随时咨询 迭代字符串并找到双行括号并使用substring方法。 正则表达式的方式..(我不太确定回合吧) 您能告诉我什么是最好的方法,并告诉我应该怎么做吗?(请不要建议太高级的解决方案) 编辑:可以使用Scanner对象以某种方式完成此操作吗?(
问题内容: 在Java中,如何获取byte []数组并从数组中删除前16个字节?我知道我可能必须通过将阵列复制到新阵列中来执行此操作。任何例子或帮助将不胜感激。 问题答案: 参见Java库中的类:
问题内容: 我目前正在翻译中编写一个针对Java字节码的玩具编译器。 我想知道是否可以在编写.class文件之前在发出的字节码中进行各种简单的窥孔优化的目录,也许是摘要。我实际上知道一些具有此功能的库,但是我想自己实现。 问题答案: 您知道Proguard吗?http://proguard.sourceforge.net/ 这是一个很棒的字节码优化器,它实现了很多优化。请参阅常见问题解答以获取列表
假设我的字符串是10个字符长。 如何删除最后一个字符? 如果我的字符串是(我不想替换字符,因为我的字符串可能包含多个字符),我只想删除最后一个字符。不管它是什么或者它发生了多少次,我都需要从我的字符串中移除最后一个字符。