我有一个应用程序,其中一些配置存储在数据库中,并且在启动时它们被注入到配置对象中。
它们的存储方式是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.val
和config.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 :(得分: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的绑定变为可变,但是你应该能够通过只绑定一次的单个可变值获得几乎相同的效果。