1

例如,我有一个要求,我使用 SuperCSV 读取 csv 文件并映射到对象。

SuperCSV 有一个要求,如果标头指定字段名称“firstName”,则它需要在类中具有 setFirstName() 方法,否则它会引发异常。

现在,如果我使用 Groovy bean,那么我不需要声明所有这些方法,只需声明变量应该适用于 SuperCSV。

但我一直在寻找一个更动态的解决方案,我们甚至不必声明这些变量。

例如,只需动态创建一个对象,并使用 groovy 的动态方法创建功能 SuperCSV 将能够找到设置器。

我查看了各种选项,例如 Expando、ExpandoMetaClass,但这些并没有达到我的目的。

任何答案将不胜感激。

这是对我有用的代码片段,可以真正有助于减少大量代码和不必要的逻辑:

    static def testBeanReader()
{
    ICsvBeanReader beanReader = null;
    try 
    {
        beanReader = new CsvBeanReader(new FileReader("src/test.csv"),
                                 CsvPreference.STANDARD_PREFERENCE);                      
    }
    catch(Exception e)      
    {

    }

    final String[] header = VirtualObject.getHeaders();
    final CellProcessor[] processors = VirtualObject.getProcessors();

    //Class c1 = createNewClass()

    //String s = createClass()
    def list = ["name", "age"]
    def c = (new GroovyShell().evaluate(createClass(list)) as Class)
    //println(c.methods.grep {it.name.startsWith("get")})

    GroovyObject groovyObject = (GroovyObject)(beanReader.read(c, header, processors))
    Object[] args = {};
    println(groovyObject.getProperty("name"))

}

     static def createClass(def list)
{
    String classDeclaration = "\nclass Test {\n"
    list.each 
    {
        classDeclaration+="def $it\n"
    } 

    classDeclaration+= """
    }
            return Test.class
                              """
    return  classDeclaration
}

这适用于 supercsv,但可用于语法几乎没有变化的通用 java 对象

4

1 回答 1

2

你不能使用 Groovy shell 来动态地构造这些类。

def c = (new GroovyShell().evaluate("""
class Test {
    def fileName // list properties here
}
return Test.class
""") as Class)

println(c.methods.grep {it.name.startsWith("set")})

def m = (c as Class).getMethod("setFileName", [Object] as Class[])
// We, and I suppose SuperCSV, can access method via Reflexion API

它不安全,但它会即时创建与 Java 兼容的类。

我不熟悉 SuperCSV,但我认为它应该使用类似反射的东西,当 Expando 或 MetaClass 解决方案将使用 Groovy 元对象协议时。

GroovyShell(或 GroovyClassLoader)将能够创建正常的类,具有工作反射。

已编辑:说明生成类的动态性质。我们首先创建类源(如我们所愿,从运行时信息,从您的 CSV 标头),然后使用它。

def createClassDeclaration()
{
    String classDeclaration = "\nclass Test {\n"
    // Here you can use your runtime information, schema, array of fields, getted from any source.
    10.times {
        classDeclaration+="def field$it\n" // declares def field1, field2, ... etc
    }
    classDeclaration += """
    }
    return Test.class
    """
    println(classDeclaration)
    return classDeclaration
}
def compile(String s)
{
    def c = (new GroovyShell().evaluate(s) as Class)
    def m = (c as Class).getMethod("setField1", [Object] as Class[])
    assert m
    println(c.methods.grep {it.name.startsWith("set")})

}

compile(createClassDeclaration())
于 2014-01-10T21:18:21.953 回答