2014-01-10 23 views
1

我有一個要求,例如我使用SuperCSV來讀取csv文件並映射到對象。用Groovy動態創建方法帶參數

SuperCSV有一個要求,如果頭部指定一個字段名稱「firstName」,它需要在類中有setFirstName()方法,否則會引發異常。

現在,如果我使用Groovy bean,那麼我不需要聲明所有這些方法,只需聲明變量應該可以工作於SuperCSV。

但我正在尋找一個更動態的解決方案,我們甚至不需要聲明這些變量。

例如,只需要創建一個對象,並使用groovy的動態方法創建功能SuperCSV就能找到setters。

我看着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對象語法

回答

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並不熟悉,但我認爲它應該使用像反射一樣的smth,當Expando或MetaClass解決方案將使用Groovy元對象協議時。

GroovyShell(或GroovyClassLoader)將能夠創建正常的類,與工作Reflexion。

編輯:說明生成的類的動態性質。並且我們首先創建類源(如我們所需,從運行時信息中,從您的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()) 
+0

如果我們在三重引號中創建字段,我們甚至不需要這樣做。如果你使用簡單的Groovy bean,那麼也可以通過聲明變量來自動獲取setter和getter。所以簡而言之,我正在尋找一個解決方案,我們甚至不必宣佈這些變量 –

+0

@sachinjain,我可以誤解你。我試着說,你可以創建這個類的聲明,在飛行中使用你的方案。字段不是通過手動列出的,您可以自動生成。我編輯了答案,試圖澄清。 – Seagull

+0

嘿Seaagull感謝它像一個魔術一樣工作了一點,因爲我是新的groovy,但終於得到它,如果有人正在尋找類似的東西我已經更新了我的原始帖子與代碼片段 –