我正在编写一个游戏引擎/库,其中我有一个事件调度程序类,它通过调用"已注册"事件处理程序类的侦听器方法来调度事件.可以通过调用适当的调度程序方法向事件调度程序注册事件处理程序/侦听器.
这显然会导致一些样板代码用于注册每个事件处理程序(以及我的引擎的其他方面都有类似的bolierplate代码),所以我想知道 - 如何在加载事件处理程序期间使用Instrumentation添加所有必需的代码class,因此编码时不需要事件调度程序的显式注册 - 在程序运行时自动添加对调度程序寄存器方法的调用.
我的理解是,为了使用Instrumentation,应该使用一些字节码修饰符API.我知道两个 - ASM和BCEL.我应该使用哪一个?显然,这是我想要做的一个简单的任务,所以我想要一个更容易学习和更好记录的那个.
编辑:这是一个具体的例子.
原始事件处理程序类:
@Handler //indicates this this class should be transformed
public class MouseEventHandler implements EventHandler<MouseEvent>
{
//hidden default constructor
public void handleEvent(MouseEvent event)
{ ... }
}
Run Code Online (Sandbox Code Playgroud)
改造后:
@Handler
public class MouseEventHandler implements EventHandler<MouseEvent>
{
public MouseEventHandler()
{
//add this line of code to default constructor
Game.getEventDispatcher().addEventHandler(this);
}
public void handleEvent(MouseEvent event)
{ ... }
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试在运行时切换类加载器:
public class Test {
public static void main(String[] args) throws Exception {
final InjectingClassLoader classLoader = new InjectingClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
Thread thread = new Thread("test") {
public void run() {
System.out.println("running...");
// approach 1
ClassLoader cl = TestProxy.class.getClassLoader();
try {
Class c = classLoader.loadClass("classloader.TestProxy");
Object o = c.newInstance();
c.getMethod("test", new Class[] {}).invoke(o);
} catch (Exception e) {
e.printStackTrace();
}
// approach 2
new TestProxy().test();
};
};
thread.setContextClassLoader(classLoader);
thread.start();
}
}
Run Code Online (Sandbox Code Playgroud)
和:
public class TestProxy {
public void test() {
ClassLoader …Run Code Online (Sandbox Code Playgroud) 我需要从现有类生成新类(通过生成java字节代码).我将分析类的方法的主体(表达式).表达式将决定我将生成什么代码.
对我来说,它是import和设置新类的源文件(与基本java文件相同)以及控制行号(当抛出异常时,stacktrace应该包含基本java文件的行号).
示例:我有文件BaseClass.java.编译器从中生成BaseClass.class.我想分析这个类文件并生成GeneratedClass.class的字节代码.当在c处抛出异常时,stacktrace应包含"BaseClass.java第3行".
BaseClass.java
1: class BaseClass {
2: void method() {
3: call();
4: }
5:}
GeneratesClaas.class
a: class GeneratedClass {
b: void generatedMethod() {
c: generatedCall();
d: }
e:}
Run Code Online (Sandbox Code Playgroud)
我的问题:是否有支持此要求的库?Javassist,ASM还是BCEL?用于此目的的是什么?提示如何做或示例代码将特别有用.
编辑: 提示哪些库不使用,因为要求不能满足也是有帮助的:).
我有以下情况..
我正在编写一些工具,对数据库运行用户输入的查询并返回结果.
最简单的方法是将结果返回为:List<String[]>但我需要更进一步.
我需要创建(在运行时)一些具有某些名称的POJO(或DTO),并为其创建字段和setter以及getter,并使用返回的数据填充它,然后将其返回给用户,并.class生成文件...
所以这里的想法是如何在运行时创建简单的类(字节码)(动态) 我做一个基本的搜索,发现很多lib 包括Apache BCEL但是我觉得我需要更简单的东西......
你对那个怎么想的?
谢谢.
我们正在使用一个包含使用JAXB注释注释的bean的库.我们使用这些类的方式取决于JAXB.换句话说,我们不需要JAXB,也不依赖于注释.
但是,由于注释存在,它们最终会被处理注释的其他类引用.这需要我在我们的应用程序中捆绑JAXB,这是不允许的,因为JAXB在javax.*包中(android不允许"核心库"包含在你的应用程序中).
所以,考虑到这一点,我正在寻找一种从编译的字节代码中删除注释的方法.我知道有用于操作字节代码的实用程序,但这对我来说是一个新的东西.任何帮助开始朝这个目的将不胜感激.
我正在研究一个简单的构建脚本,它应该从java类文件中获取一些常量,并将它们用作我文件名中的版本号.我使用Eclipse和它自己的Ant,但是将bcel-5.2.jar放在我的libs文件夹中并放入Ant调用的类路径中.
<target name="generate_version" depends="compile">
<loadproperties srcfile="${dir.dest}/MyVersion.class">
<classpath>
<fileset dir="${dir.libs}">
<include name="**/bcel*.jar"/>
</fileset>
</classpath>
<filterchain>
<classconstants/>
</filterchain>
</loadproperties>
</target>
Run Code Online (Sandbox Code Playgroud)
但不幸的是,ant任务loadproperties失败了:
build.xml:46: expected a java resource as source
Run Code Online (Sandbox Code Playgroud)
之后我尝试使用此命令行从Eclipse外部运行Ant:
set ANT_HOME=C:\Program Files\Java\ant\apache-ant-1.7.1
"%ANT_HOME%\bin\ant.bat"
Run Code Online (Sandbox Code Playgroud)
结果是
Buildfile: build.xml
init:
[echo] Building project.
[echo] ant.home: C:\Program Files\Java\ant\apache-ant-1.7.1
[echo] ant.java.version: 1.6
[echo] ant.version: Apache Ant version 1.7.1 compiled on June 27 2008
compile:
[javac] Compiling 262 source files to **********\build
[javac] Note: Some input files use or override a deprecated API.
[javac] …Run Code Online (Sandbox Code Playgroud) 似乎每个人都对Java服务提供程序有一个不愉快的画笔,你可以用一个名为META-INF/services/com.example.Interface的文件来做,但除了尝试加载正确的XML解析器之外没人用.我正在尝试使用一个使用服务提供程序API的库,并欺骗它,以便我可以提供一些运行时扩展类(使用cglib),这些类实际上不实现接口,但可以轻松地实现.
基本上,我认为我需要执行的步骤是:
但这就是我迷路的地方.例如,当库试图确定哪些实现者在那里时,它调用getResources(...),它返回一堆URL.但是getResourceAsStream(...)不接受URL,它需要"名称".名称似乎是类路径相关的,因此到处都是相同的.所以META-INF/services/com.example.Interface在它们的JAR中与META-INF/services/com.example.Interface具有相同的"名称",对吧?除了某种方式,这适用于那些爆破的XML解析器......
当然,所有这些都假设它们足够聪明/善于调用ClassLoader.getSystemClassLoader()而不是使用ClassLoader.getSystemResources(...),ClassLoader.getSystemResourceAsStream(...)等,就像后一种情况那样无法挂钩ClassLoader并提供伪造文件.
我想在那种情况下,当我的代码由Maven打包时,我可以使用BCEL来操作类文件,而不是等到运行时用cglib来完成它?
信息,例如局部变量是否"最终"存储在Java字节码中?我知道对于字段(全局变量)和方法,这些在访问标志位中找到,但似乎无法在局部变量表中找到等效项.
我对这个问题很感兴趣,因为我正在使用BCEL来检查局部变量是否是最终的,并且已经找到了AccessFlags类中的字段,方法和类的等价物.
提前致谢.
我正在寻找C或C ++中Java的BCI(字节码工具)库,以便在JVMTI代理中使用。
到目前为止,我发现的最接近的东西只是java_crw_demoKelly O'Hair几年前编写的一个演示,此演示此后一直在Sun / Oracle的教程中使用。
你还知道其他吗?
一些基本原理:我正在构建一种仪表工具,向的
java.lang.Object每个直接子类中添加一个getter方法并将此getter重载Object。因此,我不能使用Java代理。另外,出于复杂性和速度的原因,我想避免产生第二个JVM来执行检测。
对于我的论文研究,我需要将一段代码注入我没有源的测试套件中的可定义方法(在本例中为 DaCapo 基准套件,http: //dacapobench.org/ )。我论文的这一部分所基于的先前研究为此使用了字节码注入,这使我也这样做了。
我使用 Apache 的 BCEL 库 ( http://commons.apache.org/proper/commons-bcel/ ) 构建了一个小程序,该程序使我能够在其他语句之前将斐波那契算法注入到方法体中。
现在,我已经做了这个,但它不能正常工作。我注入的一些方法工作正常(因为它们因为斐波那契代码而变慢),并且运行 DaCapo 框架效果很好,而其他注入的方法会破坏代码。
问题是,我不知道为什么,即使我知道哪些方法失败了,哪些方法成功了,我也无法在损坏的方法中找到重复出现的模式。
我可以粘贴一些失败的方法,但这会使这篇文章比现在更长。所以我想知道,有什么我没有考虑或忽略的事情吗?
您将在下面找到一个示例 java 文件、它的结果和我编写的 BCEL 程序。
一个简单的例子,我有一个名为 DemoClass.java 的 java 文件:
public class DemoClass {
public static void main(String[] argv) {
System.out.println("Demo body");
test();
}
public static void test() {
System.out.println("Demo test");
}
}
Run Code Online (Sandbox Code Playgroud)
在我的 shell 中调用以下 java 命令后:
javac DemoClass.java; java -cp bcel-5.2.jar:. InjectCodeBCEL DemoClass test 123456789 ; java DemoClass
(bcel-5.2.jar文件可以在前面提到的apache网站上找到)
该程序将如下所示:
public class DemoClass {
public …Run Code Online (Sandbox Code Playgroud) 我正在玩BCEL.我不是用它来生成字节码,而是我试图检查现有编译类的结构.
我需要能够在硬盘驱动器上的任何位置指向任意.class文件,并基于此加载JavaClass对象.理想情况下,我希望避免将给定的类添加到我的类路径中.
我是Java字节码的新手.我正在使用BCEL生成字节码,但是当我尝试使用生成的代码时,我收到一条错误消息.(事后看来,看起来ObjectWeb ASM比BCEL更先进,更常用.)
这是错误消息:
Exception in thread "main" java.lang.VerifyError:
(class: cb/io/FileDescriptor, method: set
signature: (I)J)
Stack size too large
Run Code Online (Sandbox Code Playgroud)
这是方法:
// Method descriptor #4 (I)J
// Stack: 0, Locals: 1
private static long set(int arg1);
0 lconst_0
1 lreturn
Local variable table:
[pc: 0, pc: 2] local: arg1 index: 0 type: int
Run Code Online (Sandbox Code Playgroud)
据我所知,局部变量表是正确的,因为它匹配输入参数.我没有添加'this'变量,因为该方法是静态的.
如果我没弄错的话,lconst_0会将一个长值0加载到堆栈上,并且lreturn会消耗该值并返回它.
我究竟做错了什么?这里有足够的信息可以说明吗?
谢谢!
我有以下课程:
package some.clazz.client;
import some.clazz.SomeClass;
public class SomeClassClient {
...
public SomeClass getProc();
...
}
Run Code Online (Sandbox Code Playgroud)
我已经通过在Maven 插件中使用ByteBuddy 转换getProc()从SomeClassClient类字节码中删除/缩小/删除了这个Java 方法。但是语句仍然存在并由!new MemberRemoval().stripMethods(ElementMatcher);net.bytebuddy:byte-buddy-maven-pluginimport some.clazz.SomeClass;CFR Java Decompiler
SomeClass类中没有任何其他对类的引用SomeClassClient。
如何从字节码中删除这个导入语句(我真的假设它位于常量池中)?因为我在尝试使用“SomeClassClient”类时仍然遇到 ClassNotFoundException。
我的课
public class MethodsRemover implements net.bytebuddy.build.Plugin {
...
@Override
public DynamicType.Builder<?> apply(DynamicType.Builder<?> builder,
TypeDescription typeDescription,
ClassFileLocator classFileLocator) {
try{
return builder.visit(new MemberRemoval().stripMethods(
ElementMatchers.any().and(
isAnnotatedWith(Transient.class)
.and(
t -> {
log.info(
"ByteBuddy transforming class: {}, strip method: {}",
typeDescription.getName(),
t
);
return true;
}
) …Run Code Online (Sandbox Code Playgroud) bcel ×13
java ×13
bytecode ×6
assembly ×2
android ×1
annotations ×1
ant ×1
byte-buddy ×1
c ×1
cglib ×1
classloader ×1
dacapo ×1
javassist ×1
jvmti ×1
provider ×1
reflection ×1
service ×1