Search code examples
javasubclasscglib

Java - creating a subclass dynamically


I'd like to create a subclass programatically. I guess I have few options - Javassist, CGLib, BCEL, or ASM.

The use case is that one app's internals are class-oriented, and extensions are class-based. Therefore I can't have a single class as a base for multiple extensions driven by externalized scripts.

Now - how would I do that? I've found examples with intercepting method calls, field access, initialization etc. But nothing about subclassing.

I'd like to end up with a class which:

  • has a name which I want.
  • is a (direct, at best) subclass of a given class
  • copies the constructor(s) from the parent class (or calls super(...))
  • eventually, I'd like to give it some annotations.

I know it's possible because various dynamic languages integrations, like GroovyClassLoader, can do that.


Solution

  • It's quite easy with 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 dependency:

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