我有一个Groovy类,可以动态创建另一个类:

package javainterop3

import groovy.lang.Closure;
import groovy.lang.GroovyClassLoader;

class DynamicClass {

    GroovyClassLoader loader
    String name
    Class cls
    def imports
    def fields
    def methods

    def DynamicClass() {
        imports = []
        fields = [:]
        methods = [:]
    }

    def setLoader(GroovyClassLoader loader)
    {
        this.loader = loader
    }

    def setName(String name) {
        this.name = name
    }

    def setImports(Set imports) {
        this.imports = imports.each{importClass ->
            "${importClass.getPackage().getName()}" +
                ".${importClass.getSimpleName()}"
        }
    }

    def addFields(Map fields) {
        this.fields = fields
    }

    def addMethods(Map methods) {
        this.methods = methods
    }

    def createClass() {

        def templateText = '''
<%imports.each {%>import $it\n <% } %>
class $name
{
<%fields.each {%>    $it.value $it.key \n<% } %>
}
'''
        fields.each {
            it.value = it.value.simpleName
        }

        def data = [name: name, imports: imports, fields: fields]

        def engine = new groovy.text.SimpleTemplateEngine()
        def template = engine.createTemplate(templateText)
        def result = template.make(data)
        println result.toString()
        cls = loader.parseClass(result.toString())
        methods.each {
            cls.metaClass."$it.key" = it.value
        }
    }
}


我现在正在尝试为创建新类创建一个简单的生成器:

package javainterop3

import java.util.Map;

class ClassBuilder extends BuilderSupport{

    private DynamicClass dynamicClass

    @Override
    protected void setParent(Object parent, Object child) {
    }

    @Override
    protected Object createNode(Object name) {
        if(name == 'newClass')
        {
            dynamicClass = new DynamicClass()
        }
        else
        {
            throw new IllegalArgumentException(name)
        }
    }

    @Override
    protected Object createNode(Object name, Object value) {

        if(name == 'loader')
        {
            dynamicClass.setLoader(value)
        }
        else if(name == 'name')
        {
            dynamicClass.setName(value)
        }
        else if(name == 'imports')
        {
            println value
            dynamicClass.setImports(value)
        }
        else
        {
            throw new IllegalArgumentException(name)
        }
    }

    @Override
    protected Object createNode(Object name, Map attributes) {
        if(name == 'fields')
        {
            dynamicClass.setFields(attributes)
        }
        else if(name == 'methods')
        {
            dynamicClass.setMethods(attributes)
        }
        else
        {
            throw new IllegalArgumentException(name)
        }
    }

    @Override
    protected Object createNode(Object name, Map attributes, Object value) {
        return null
    }

    @Override
    protected void nodeCompleted(Object parent, Object node)
    {
        if(node instanceof DynamicClass)
        {
            node.createClass()
        }
    }

    public Class getDynamicClass()
    {
        return dynamicClass.cls
    }

}


这是一个创建简单的Groovy类的测试脚本:

package javainterop3

import java.util.Calendar
import java.util.Random

def builder = new ClassBuilder()

builder.newClass{

    loader this.class.classLoader

    name 'MyClass'

    imports Calendar, Random, UUID

    fields 'field1' : Integer,
           'field2' : Integer

    methods 'sum' : {return field1 + field2},
            'product' : {return field1 * field2},
            'testCalendar' : {return Calendar.getInstance().getTime()},
            'testRandom' : {return (new Random()).nextInt()}

}


我的问题是使用imports方法。应该接受要导入的Java类的列表。在基础类(DynamicClass)中,导入是一个列表,但我不确定如何将列表传递给构建器,或者不确定createNode()重载来处理imports方法。我以为参数不是在createNode(Object name,Object value)中处理它的映射,但是我得到了这个异常:

Caught: groovy.lang.MissingMethodException: No signature of method: \
  javainterop3.Test.imports() is applicable for argument types:     \
  (java.lang.Class, java.lang.Class, java.lang.Class) values:       \
  [class java.util.Calendar, class java.util.Random, ...]


“加载程序”和“名称”在createNode(对象名称,对象值)中被拦截,在createNode(对象名称,地图属性)中的“字段”和“方法”中被拦截,但是我不确定如何处理“导入”一个列表。我已经尝试过每个createNode重载,但无法使其工作。

最佳答案

它与重写的方法不匹配。一种方法是进行以下修改:

//Dynamic Class
def setImports(Class importClass) {
    this.imports << "$importClass.name"
}


然后在建造时

builder.newClass{

    loader this.class.classLoader

    name 'MyClass'

    [Calendar, UUID, Random].each { imports it }

    fields 'field1' : Integer,
           'field2' : Integer

    methods 'sum' : {return field1 + field2},
            'product' : {return field1 * field2},
            'testCalendar' : {return Calendar.getInstance().getTime()},
            'testRandom' : {return (new Random()).nextInt()}

}

10-04 23:43