0

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

所以解析后就变成了这样的map: [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.val并且config.val.moreConfig- 则moreConfig不会被分配。

一段时间后,我决定通过value自动在所有路径中声明键来分配值,但我仍然很好奇是否有办法在绑定中重新定义值?

还是Binding在 groovy 中声明的值变得可变?

更新: 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]]
4

2 回答 2

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
  }

}
于 2012-08-13T11:33:40.777 回答
0

我不知道是否可以将键绑定到值可变,但您应该能够使用仅绑定一次的单个可变值获得几乎相同的效果。

于 2012-08-13T10:56:22.183 回答