groovyclassloaderdynamic-class-loaders

Groovy: writing dynamically compiled class to disc


In my app I need to compile classes / scripts in runtime.

as a Class:

Class<? extends LoginAdapter> clazz = groovyClassLoader.loadClass name
LoginAdapter la = clazz.newInstance id, logo

or as a Closure:

Closure action = groovyShell.evaluate( script, name ) as Closure

Both ways work like charm.

Now I need to be able to write the compiled classes/scripts to some persistant storage (disc) and later restore them back without compiling from scratch.

How can this be done?


Solution

  • For those who might be interested, this is my programming kata:

    class Base {
      String answer() { null }
      String question() { 'WHAT IS.... ?' }
    }
    
    class ClazzSpec extends Specification {
    
      def "test compile"() {
        given:
        String packageName = 'some.pckg'
        String body = """
    package $packageName
    
    class SomeClass extends Base {
      Closure cl = { a -> println a }
      @Override String answer(){ '42' }
      String json( m ){ JsonOutput.toJson( m ) }
      String longOne( int times ){ 
        times.times{ sleep 100 }
        'done'
      }
    }
    """
    
        CompilerConfiguration cc = new CompilerConfiguration( targetDirectory:new File( './out' ) )
        ImportCustomizer imp = new ImportCustomizer()
        imp.addStarImports 'groovy.json', Base.package.name
        cc.addCompilationCustomizers imp, new ASTTransformationCustomizer( value:1, TimedInterrupt )
    
        new Compiler( cc ).compile packageName + '.SomeClass', body
    
        File base = new File( './out' )
    
        GroovyClassLoader gcl = new GroovyClassLoader()
        gcl.addClasspath './out'
        Class clazz = gcl.loadClass 'some.pckg.SomeClass'
    
        when:
        def inst = clazz.newInstance()
    
        then:
        inst.question() == 'WHAT IS.... ?'
        inst.answer() == '42'
        inst.json( [ q:42 ] ) == '{"q":42}'
        inst.longOne( 2 ) == 'done'
    
        when:
        inst.longOne 11
    
        then:
        thrown TimeoutException
      }
    
    }