Groovy绑定:重新绑定值

时间:2012-08-13 10:50:35

标签: binding groovy immutability

我有一个应用程序,其中一些配置存储在数据库中,并且在启动时它们被注入到配置对象中。 它们的存储方式是object path字符串,如:"some.config.value"

所以在解析之后就变成了这种地图: [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]]

2 个答案:

答案 0 :(得分:1)

我无法从您的问题中看到您正在尝试做什么,但这会为您提供您所说的输入所表达的输出:

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

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

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

你也可以通过玩Closure代表来做这样有趣的事情:

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
  }

}

答案 1 :(得分:0)

我不知道是否可以将key到value的绑定变为可变,但是你应该能够通过只绑定一次的单个可变值获得几乎相同的效果。