动态创建Groovy类

给定一个类名,我想动态创建一个Groovy类,向其添加属性和方法。我使用创建新类

instance = this.class.classLoader.parseClass(

"public class $name {}")

对于我使用的方法

instance.metaClass."$it.key" = it.value

其中it.key是字符串(方法名),it.value是闭包。这很方便,因为我可以指定方法参数类型并进行类型检查。但是,如果不给它赋值,就无法指定动态创建的属性类型。我可以通过显式定义属性的getter和setter来解决此问题。这可行,但是metaClass.name

= value或metaClass.getName =

{}似乎都没有在类中实际创建字段,因为Java字段运算符不适用于创建的属性。是否可以在Groovy类中添加属性并指定其类型,而无需为其分配初始值或显式定义getter和setter方法?有没有一种方法可以向Groovy类添加新字段?这是脚本:

class SomeClass {

Integer p1

String p2

}

class ClassBuilder {

def name

def instance

def properties

def methods

def ClassBuilder() {

properties = [:]

methods = [:]

}

def set_name(name) {

this.name = name

}

def add_property(name, type) {

properties[name] = type

}

def add_method(name, closure) {

methods[name] = closure

}

def get_instance() {

instance = this.class.classLoader.parseClass(

"public class $name {}")

properties.each {

instance.metaClass."$it.key" = null

//doesn't work

instance.metaClass."$it.key".type = it.value

}

methods.each {

instance.metaClass."$it.key" = it.value

}

return instance

}

}

builder = new ClassBuilder()

builder.set_name('MyClass')

builder.add_property('property1', String)

builder.add_property('property2', SomeClass)

builder.add_method('method1', {SomeClass obj -> println obj})

builder.add_method('setProperty2', {SomeClass obj -> this.property2 = obj})

builder.add_method('getProperty2', {return this.property2})

builder.add_method('method2', {return property1 + property2})

c = builder.get_instance()

i = c.newInstance()

i.property1 = new SomeClass()

i.property2 = 5

//i.method2() //throws GroovyCastException

//i.property2 = 'throws GroovyCastException'

//i.@property1 = 'throws MissingFieldException'

//No such field: property2 for class: MyClass

//i.@property2 = new SomeClass()

i.method1(new SomeClass())

//i.method1('throws MissingMethodException')

用例是这样的:我用Java定义接口或基类。用户在Groovy中实现接口或扩展基类,然后将该类传递回Java以供主应用程序使用。用户不是程序员,因此他们使用简单的DSL定义类,而我使用构建器构造实际的类。我仍在尝试使用Groovy

/ JRuby和Java interop(这两种语言都是新的)。

回答:

我已经或多或少地能够通过使用GroovyClassLoader和SimpleTemplateEngine使其工作。这是代码:

class ClassBuilder {

GroovyClassLoader loader

String name

Class cls

def imports

def fields

def methods

def ClassBuilder(GroovyClassLoader loader) {

this.loader = loader

imports = []

fields = [:]

methods = [:]

}

def setName(String name) {

this.name = name

}

def addImport(Class importClass) {

imports << "${importClass.getPackage().getName()}" +

".${importClass.getSimpleName()}"

}

def addField(String name, Class type) {

fields[name] = type.simpleName

}

def addMethod(String name, Closure closure) {

methods[name] = closure

}

def getCreatedClass() {

def templateText = '''

<%imports.each {%>import $it\n <% } %>

class $name

{

<%fields.each {%> $it.value $it.key \n<% } %>

}

'''

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

def engine = new groovy.text.SimpleTemplateEngine()

def template = engine.createTemplate(templateText)

def result = template.make(data)

cls = loader.parseClass(result.toString())

methods.each {

cls.metaClass."$it.key" = it.value

}

return cls

}

}

这是我如何使用它动态创建类的示例:

import java.util.Calendar

def builder = new ClassBuilder(this.class.classLoader)

builder.setName("MyClass");

builder.addImport(Calendar)

builder.addField('field1', Integer)

builder.addField('field2', Integer)

builder.addMethod('sum') { field1 + field2 }

builder.addMethod('product') { field1 * field2 }

builder.addMethod('testCalendar') {

println Calendar.getInstance().getTime()

}

Class myClass = builder.getCreatedClass()

def myInstance = myClass.newInstance()

myInstance.field1 = 1

myInstance.field2 = 2

println myInstance.sum()

println myInstance.product()

myInstance.setField2(1500)

println myInstance.getField2()

myInstance.testCalendar()

以上是 动态创建Groovy类 的全部内容, 来源链接: utcz.com/qa/418440.html

回到顶部