当前位置: 首页 > 面试题库 >

动态创建Groovy类

亢建白
2023-03-14
问题内容

给定一个类名,我想动态创建一个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()


 类似资料:
  • 问题内容: 我需要动态创建一个类。为了更详细,我需要动态创建Django类的子类。 通过“动态”,我打算基于用户提供的配置创建一个类。 例如 我想要一个命名为该类的子类的类。 该类应具有所选属性的列表。 ....在这种情况下 有什么有用的提示吗?:) 问题答案: 您可以通过调用内置函数并传递适当的参数来动态创建类,例如: 它适用于新型类。我不确定这是否也适用于老式类。

  • 问题内容: 你好,我有这个设置 我需要为每个按钮获取以下内容 在Java中是否可以为我声明的每个按钮动态创建此按钮?因为当我有5个按钮时,我不需要3x5 = 15行代码,而是只有几行具有动态创建的按钮。 问题答案: 编写一个小循环并将您的按钮存储在数组中:

  • 你好,我已经准备好了 我需要为每个按钮获得以下内容 在Java中,是否可以为我声明的每个按钮动态创建它?因为当我有5个按钮时,我不希望3x5=15行代码,而只希望有几行动态创建的按钮。

  • 我们知道,type() 函数属于 Python 内置函数,通常用来查看某个变量的具体类型。其实,type() 函数还有一个更高级的用法,即创建一个自定义类型(也就是创建一个类)。 type() 函数的语法格式有 2 种,分别如下: type(obj)  type(name, bases, dict) 以上这 2 种语法格式,各参数的含义及功能分别是: 第一种语法格式用来查看某个变量(类对象)的具体

  • 问题内容: 我在mysql上创建数据库。首先创建主体表,每个表平均有30列。日志表的标准是引用表的pk加上每列*2。像这样: 参考表: 日志表: 现在,我想要创建一个过程,在该过程中,我将表名作为参数传递,并生成表日志查询并执行它。 做这个的最好方式是什么? 问题答案: 为了使一个字符串代表一个表(或数据库)名称,您将需要用变量连接查询字符串,并在存储过程中准备/执行一条语句。这是一个基本示例。

  • 问题内容: 我陷入GWT CellTable的问题。我需要动态创建单元表,而我没有实体(Bean)类。我已经看到了所有celltable的示例,并且在没有实体类的情况下进行了大量搜索。 我需要根据数据库中存储的一些元数据动态填充表。我可以创建表结构 考虑有两个类,一个是GRID,另一个是COLUMN,用于元数据和列定义。GRID将具有COLUMNS的列表作为列定义 现在,我需要从数据库中获取网格并