2013-06-23 49 views
10

我想以编程方式创建子类。 我想我有几个选项 - Javassist,CGLib,BCEL或ASM。Java - 动态创建子类

用例是一个应用程序的内部是面向类的,扩展是基于类的。因此,我无法将单个类作为由外部化脚本驱动的多个扩展的基础。

现在 - 我该怎么做?我发现拦截方法调用,字段访问,初始化等的例子,但没有关于子类。

我想带班结束了,其中:

  • 有我想要的名称。
  • 是父类的给定类
  • 拷贝构造函数(S)的(直接,最好)的子类(或称super(...)
  • 最后,我想给它一些注解。

我知道这是可能的,因为各种动态语言集成,如GroovyClassLoader,可以做到这一点。

回答

5

这是很容易用Javassist:

import javassist.CannotCompileException; 
import javassist.ClassPool; 
import javassist.CtClass; 
import javassist.NotFoundException; 

static Class<? extends DefinitionBasedMigrator> createClass(String fullName) 
     throws NotFoundException, CannotCompileException 
{ 
    ClassPool pool = ClassPool.getDefault(); 

    // Create the class. 
    CtClass subClass = pool.makeClass(fullName); 
    final CtClass superClass = pool.get(DefinitionBasedMigrator.class.getName()); 
    subClass.setSuperclass(superClass); 
    subClass.setModifiers(Modifier.PUBLIC); 

    // Add a constructor which will call super(...); 
    CtClass[] params = new CtClass[]{ 
     pool.get(MigratorDefinition.class.getName()), 
     pool.get(GlobalConfiguration.class.getName()) 
    }; 
    final CtConstructor ctor = CtNewConstructor.make(params, null, CtNewConstructor.PASS_PARAMS, null, null, subClass); 
    subClass.addConstructor(ctor); 

    return subClass.toClass(); 
} 

Maven的依赖性:

<!-- https://mvnrepository.com/artifact/org.javassist/javassist --> 
<dependency> 
    <groupId>org.javassist</groupId> 
    <artifactId>javassist</artifactId> 
    <version>3.22.0-GA</version> 
</dependency> 
2

Java代理可能能够做你需要什么 - 它们基本上允许你动态上的顶层功能对象,因为您可以拦截对该对象的任何方法调用,并自己处理它们或将方法调用派发到基础类。根据您要做的事情,可能会得到与通过动态创建子类相同的结果

Oracle在其网站上有一个decent introduction(URL引用Java版本1.4.2,但我不认为这种行为在更新的版本中已经改变)。这是一个more concise example,它代表了代理代码的外观。

也可以使用直接字节码操作来做事情(ASM framework支持),但我想使用代理将是一个更简单的方法。

+0

其实我首先看了代理,但由于复杂性而留下了代码。 Javassist更容易。而且,代理需要一个接口,不能像正常的类那样进一步重写......无论如何+1 –

7

我特别喜欢的一个库可能在这里使用; Bytebuddy

Class<?> dynamicType = new ByteBuddy() 
    .subclass(Object.class) 
    .method(ElementMatchers.named("toString")) 
    .intercept(FixedValue.value("Hello World!")) 
    .make() 
    .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) 
    .getLoaded(); 

这是令人难以置信的灵活性和绝对值得一试,如果你想保持你的头发,我亲自找到了Javassist的大量使用可以得到相当难看:

例直接从着陆页取并且有时候会变得凌乱,bytebuddy感觉像是一个需要呼吸的新鲜空气!

Rafael Winterhalter也在StackOverflow上处于活动状态,它可以发现任何你不确定的事情。

编辑:我的道歉为necroposting。当朋友将问题链接起来并忘记检查日期时登陆此处。