2012-08-13 26 views
0

我有一個應用程序,其中一些配置存儲在數據庫中,啓動時它們被注入配置對象。 它們的存儲方式是object path字符串,如:"some.config.value"Groovy綁定:rebind值

所以解析後,就變成這個樣圖: [some: [config: [value: [:]]]]

我實現了這個使用Binding,這裏是代碼:

Binding bind = new Binding() 
bind.tmp = bean // Bean is an object where it is being injected 

String[] traverse = stringPath.split(/\./) 
def shift = bind.tmp 
traverse.eachWithIndex { String it, int i -> 
    if (it) { 
     if (!(shift instanceof Map)) { 
      shift = ["$it": [:]] // <-- Doesn't work 
     } else { 
      if (!shift?.containsKey(it)) { 
       // val - is a value to assign to last key in path 
       shift[it] = (i + 1 == traverse.size()) ? val : [:] 
      } else if (shift?.containsKey(it) && (i + 1 == traverse.size())) { 
       shift[it] = val 
      } 
     } 

     shift = shift[it] 
    } 
} 

這種方法的問題是,如果我已經定義鍵綁定,我似乎無法重新定義它(在shift = ["$it": [:]])。

例如:如果我有config.valconfig.val.moreConfig - 則不會分配moreConfig

經過一段時間,我只是決定通過在所有路徑中自動聲明value鍵來指定值,但我仍然好奇是否有方法來重新定義綁定中的值?

或者在groovy中通過Binding聲明的值變爲可變嗎?

更新: bean是一個哈希映射與硬編碼配置。它可能只是一張空白的地圖。 基本上我在做的是在那裏注入更多有價值的地圖。

如果我有值的鏈條:

  • "config.some.var" = 10
  • "config.some.var2" = 20
  • "config.some.var.more" = 30

會導致:

[config: [ 
    some: [ 
     var: 10, 
     var2: 20 
    ] 
]] 

預期的最新數據將被丟棄,因爲它的值已經爲10。我想要的是用最新的值覆蓋第一個值,同時保持所有其他值處於相同的深度級別。

上面的代碼產生如下:

def bean = [someOtherConfig: []] 
convert bean, 'config.var', 10 
convert bean, 'config.var2', 20 
convert bean, 'config.var.more', 30 
assert bean == [someOtherConfig: [], config: [var: 10, var2: 20]] 
+0

你能提供一個運行的例子,但不工作,因爲你想?我不能運行上面的示例,因爲我不知道'bean'應該是什麼...... – 2012-08-13 11:22:45

回答

1

我無法從你的問題看你想要做什麼,但是這給你,你說你會從輸入期望的輸出你描述:

def build = { name -> 
    name.split(/\./).reverse().inject([:]) { m, n -> 
    [ (n): m ] 
    } 
} 

def map = build('some.config.value') 

assert map == ['some':['config':['value':[:]]]] 

你也可以做一些有趣的像這樣的事情通過與閉幕代表玩:

def map = new ConfigBuilder().build { 
    config.some.var = 10 
    config.some.var2 = 20 
    config.some.var.more = 30 
} 

assert map == [config:[some:[var:10, var2:20]]] 

// Implementation 

class ConfigBuilder { 
    private Map map, curr 
    private boolean ignore = false 

    ConfigBuilder(Map initial=[:]) { 
    this.map = initial 
    this.curr = this.map 
    } 

    def build(Closure c) { 
    c.delegate = this 
    c.resolveStrategy = Closure.DELEGATE_FIRST 
    c() 
    map 
    } 

    def propertyMissing(String name) { 
    if(ignore) return this 
    if(curr[ name ] == null) { 
     curr[ name ] = [:] 
     curr = curr[ name ] 
    } 
    else if(curr[ name ] instanceof Map) { 
     curr = curr[ name ] 
    } 
    else { 
     ignore = true 
    } 
    this 
    } 

    void setProperty(String name, value) { 
    if(!ignore) { 
     curr[ name ] = value 
    } 
    // Reset and go again 
    ignore = false 
    curr = map 
    value 
    } 

} 
+0

感謝您的回答。我已經更新了我的問題,但同時會嘗試調整您的示例。 – 2012-08-13 12:23:15

+0

@liaant你看過[使用'ConfigSlurper'](http://groovy.codehaus.org/gapi/groovy/util/ConfigSlurper.html)嗎?它不採用默認值,並會在重新分配時拋出異常,但也可能有所幫助。 – 2012-08-13 12:53:30

+0

@liaant發佈了一個更新到我的答案...沒有經過巨大的測試,但可能是有趣的... – 2012-08-13 13:04:20

0

我不知道是否有可能作出關鍵性的結合值可變的,但你應該能夠得到一個單一的幾乎相同的效果您只綁定一次的可變值。