0

一部の構成がデータベースに保存され、起動時に構成オブジェクトに挿入されるアプリケーションがあります。それらが格納される方法は、次の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.valand config.val.moreConfig- thenを持っていれば、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 に答える