gpt4 book ai didi

java - 动态创建 Groovy 类

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:26:38 25 4
gpt4 key购买 nike

给定一个类名,我想动态创建一个 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中定义了一个接口(interface)或者一个基类。用户在 Groovy 中实现接口(interface)或扩展基类,并将该类传递回 Java 以供主应用程序使用。用户不是程序员,所以他们使用简单的 DSL 定义类,而我使用构建器构建实际的类。我仍在试验 Groovy/JRuby 和 Java 互操作(这两种语言都是新的)。

最佳答案

通过使用 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()

关于java - 动态创建 Groovy 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23160278/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com