diff --git a/src/main/java/org/redkale/util/AnyValue.java b/src/main/java/org/redkale/util/AnyValue.java index c02af7888..65d0c9fd4 100644 --- a/src/main/java/org/redkale/util/AnyValue.java +++ b/src/main/java/org/redkale/util/AnyValue.java @@ -54,6 +54,8 @@ public abstract class AnyValue { private Entry[] anyEntrys = new Entry[0]; + private int parentArrayIndex = -1; //只可能被loadFromProperties方法赋值 + /** * 创建空的DefaultAnyValue对象 * @@ -135,6 +137,76 @@ public abstract class AnyValue { return rs; } + /** + * 复制一份对象 + * + * @return DefaultAnyValue对象 + */ + @Override + public DefaultAnyValue copy() { + DefaultAnyValue rs = new DefaultAnyValue(this.ignoreCase); + if (this.stringEntrys != null) { + rs.stringEntrys = new Entry[this.stringEntrys.length]; + for (int i = 0; i < rs.stringEntrys.length; i++) { + Entry en = this.stringEntrys[i]; + if (en == null) continue; + rs.stringEntrys[i] = new Entry(en.name, en.value); + } + } + if (this.anyEntrys != null) { + rs.anyEntrys = new Entry[this.anyEntrys.length]; + for (int i = 0; i < rs.anyEntrys.length; i++) { + Entry en = this.anyEntrys[i]; + if (en == null) continue; + rs.anyEntrys[i] = new Entry(en.name, en.value == null ? null : en.value.copy()); + } + } + return rs; + } + + /** + * 将另一个对象合并过来 + * + * @param node0 代合并对象 + * + * @return AnyValue + */ + @Override + public DefaultAnyValue merge(AnyValue node0) { + if (node0 == null) return this; + if (node0 == this) throw new IllegalArgumentException(); + DefaultAnyValue node = (DefaultAnyValue) node0; + if (node.stringEntrys != null) { + for (Entry en : node.stringEntrys) { + if (en == null) continue; + setValue(en.name, en.value); + } + } + if (node.anyEntrys != null) { + for (Entry en : node.anyEntrys) { + if (en == null) continue; + AnyValue[] ns = getAnyValues(en.name); + if (ns == null || ns.length < 1) { + addValue(en.name, en.value); + } else { + boolean ok = false; + for (AnyValue item : ns) { + if (item == null) continue; + if (en.value.parentArrayIndex == ((DefaultAnyValue) item).parentArrayIndex) { + item.merge(en.value); + ok = true; + break; + } + } + if (!ok) { + addValue(en.name, en.value); + } + } + } + } + return this; + } + /** * 合并两个AnyValue对象, 会去重, 没有的才增加 * @@ -147,7 +219,7 @@ public abstract class AnyValue { final Entry[] strings = av.getStringEntrys(); if (strings == null) return this; for (Entry en : strings) { - if (getValue(en.name) == null) this.addValue(en.name, en.value); + if (!existsValue(en.name)) this.addValue(en.name, en.value); } return this; } @@ -311,7 +383,11 @@ public abstract class AnyValue { @Override public String toString() { - return toString(0); + return toString(0, (any, space) -> { + int index = ((DefaultAnyValue) any).parentArrayIndex; + if (index < 0) return null; + return new StringBuilder().append(space).append(" $index: ").append(index).append(",\r\n"); + }); } public DefaultAnyValue clear() { @@ -322,7 +398,7 @@ public abstract class AnyValue { public DefaultAnyValue setValue(String name, String value) { if (name == null) return this; - if (getValue(name) == null) { + if (!existsValue(name)) { this.addValue(name, value); } else { for (Entry en : this.stringEntrys) { @@ -337,7 +413,7 @@ public abstract class AnyValue { public DefaultAnyValue setValue(String name, AnyValue value) { if (name == null) return this; - if (getValue(name) == null) { + if (!existsValue(name)) { this.addValue(name, value); } else { for (Entry en : this.anyEntrys) { @@ -419,6 +495,14 @@ public abstract class AnyValue { return null; } + public boolean existsValue(String name) { + for (Entry en : this.stringEntrys) { + if (predicate.test(en.name, name)) { + return true; + } + } + return false; + } } /** @@ -662,8 +746,15 @@ public abstract class AnyValue { parent = child; } else { //数组或Map结构, []中间是数字开头的视为数组,其他视为map String itemField = item.substring(0, pos); //[前面一部分 - String itemIndex = item.substring(pos + 1, item.indexOf(']')); - if (!itemIndex.isEmpty() && itemIndex.charAt(0) >= '0' && itemIndex.charAt(0) <= '9') { //数组 + String keyOrIndex = item.substring(pos + 1, item.indexOf(']')); + int realIndex = -1; + if (!keyOrIndex.isEmpty() && keyOrIndex.charAt(0) >= '0' && keyOrIndex.charAt(0) <= '9') { + try { + realIndex = Integer.parseInt(keyOrIndex); + } catch (NumberFormatException e) { + } + } + if (realIndex >= 0) { //数组 String prefixKey = ""; for (int j = 0; j < i; j++) { prefixKey += keys[j] + "."; @@ -684,7 +775,9 @@ public abstract class AnyValue { if (!keymap.containsKey(prefixKey2)) { DefaultAnyValue vv = new DefaultAnyValue(); keymap.put(prefixKey2, vv); - sortmap.put(Integer.parseInt(ks[ii].substring(ks[ii].indexOf('[') + 1, ks[ii].lastIndexOf(']'))), vv); + int aindex = Integer.parseInt(ks[ii].substring(ks[ii].indexOf('[') + 1, ks[ii].lastIndexOf(']'))); + vv.parentArrayIndex = aindex; + sortmap.put(aindex, vv); } }); prefixArray.putAll(keymap); @@ -699,11 +792,11 @@ public abstract class AnyValue { field = new DefaultAnyValue(); parent.addValue(itemField, field); } - DefaultAnyValue index = (DefaultAnyValue) field.getAnyValue(itemIndex); + DefaultAnyValue index = (DefaultAnyValue) field.getAnyValue(keyOrIndex); if (index == null) { index = new DefaultAnyValue(); - if (nameName != null) index.setValue(nameName, itemIndex); - field.addValue(itemIndex, index); + if (nameName != null) index.setValue(nameName, keyOrIndex); + field.addValue(keyOrIndex, index); } parent = index; } @@ -838,25 +931,46 @@ public abstract class AnyValue { /** * 当前AnyValue对象字符串化 * - * @param indent 缩进长度 + * @param indent 缩进长度 + * @param prefixFunc 扩展函数 * * @return String */ - public String toString(int indent) { //indent: 缩进长度 + public String toString(int indent, BiFunction prefixFunc) { //indent: 缩进长度 if (indent < 0) indent = 0; final String space = " ".repeat(indent); StringBuilder sb = new StringBuilder(); sb.append("{\r\n"); + if (prefixFunc != null) { + CharSequence v = prefixFunc.apply(this, space); + if (v != null) sb.append(v); + } for (Entry en : getStringEntrys()) { sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n"); } for (Entry en : getAnyEntrys()) { - sb.append(space).append(" '").append(en.name).append("': ").append(en.value.toString(indent + 4)).append(",\r\n"); + sb.append(space).append(" '").append(en.name).append("': ").append(en.value.toString(indent + 4, prefixFunc)).append(",\r\n"); } sb.append(space).append('}'); return sb.toString(); } + /** + * 复制一份 + * + * @return AnyValue + */ + public abstract AnyValue copy(); + + /** + * 将另一个对象合并过来 + * + * @param node 代合并对象 + * + * @return AnyValue + */ + public abstract AnyValue merge(AnyValue node); + /** * 回调子节点 * diff --git a/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java b/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java index ee956f941..9b917e0fb 100644 --- a/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java +++ b/src/test/java/org/redkale/test/util/AnyValuePropertiesTest.java @@ -34,46 +34,76 @@ public class AnyValuePropertiesTest { properties.put("redkale.mmm.node[20]", "n20"); String result = "{\r\n" - + " 'redkale': '{\r\n" - + " 'source': '{\r\n" - + " 'my': '{\r\n" + + " 'redkale': {\r\n" + + " 'source': {\r\n" + + " 'my': {\r\n" + " 'sss': 'my s',\r\n" + " 'ttt': 'my t',\r\n" - + " }',\r\n" - + " 'you': '{\r\n" + + " },\r\n" + + " 'you': {\r\n" + " 'ttt': 'you t',\r\n" + " 'sss': 'you s',\r\n" - + " }',\r\n" - + " }',\r\n" - + " 'ddd': '{\r\n" + + " },\r\n" + + " },\r\n" + + " 'ddd': {\r\n" + + " $index: 0,\r\n" + " 'ww': 'ww 0',\r\n" + " 'nn': 'nn 0',\r\n" - + " }',\r\n" - + " 'ddd': '{\r\n" + + " },\r\n" + + " 'ddd': {\r\n" + + " $index: 2,\r\n" + " 'ww': 'ww 2',\r\n" + " 'nn': 'nn 2',\r\n" - + " }',\r\n" - + " 'ddd': '{\r\n" + + " },\r\n" + + " 'ddd': {\r\n" + + " $index: 10,\r\n" + " 'ww': 'ww 10',\r\n" + " 'nn': 'nn 10',\r\n" - + " }',\r\n" - + " 'mmm': '{\r\n" + + " },\r\n" + + " 'mmm': {\r\n" + " 'node': 'n0',\r\n" + " 'node': 'n5',\r\n" + " 'node': 'n20',\r\n" - + " }',\r\n" - + " 'bbb': '{\r\n" + + " },\r\n" + + " 'bbb': {\r\n" + " 'sss': 'value s',\r\n" - + " 'qqq': '{\r\n" + + " 'qqq': {\r\n" + " 'rrr': 'value r',\r\n" - + " }',\r\n" - + " }',\r\n" - + " 'aaa': '{\r\n" + + " },\r\n" + + " },\r\n" + + " 'aaa': {\r\n" + " 'ppp': 'value p',\r\n" + " 'ooo': 'value o',\r\n" - + " }',\r\n" - + " }',\r\n" + + " },\r\n" + + " },\r\n" + "}"; Assertions.assertEquals(result, AnyValue.loadFromProperties(properties).toString()); } + + @Test + public void run2() { + Properties prop = new Properties(); + prop.put("redkale.name", "myname"); + prop.put("redkale.node[3].id", "333"); + prop.put("redkale.node[3].desc", "haha3"); + prop.put("redkale.node[1].id", "111"); + prop.put("redkale.node[1].desc", "haha1"); + prop.put("redkale.node[2].id", "222"); + prop.put("redkale.node[2].desc", "haha2"); + + AnyValue conf = AnyValue.loadFromProperties(prop); + //System.out.println(conf); + + Properties prop2 = new Properties(); + prop2.put("redkale.name", "myname too"); + prop2.put("redkale.node[3].id", "999"); + prop2.put("redkale.node[3].desc", "haha9"); + prop2.put("redkale.node[4].id", "444"); + prop2.put("redkale.node[4].desc", "haha4"); + AnyValue conf2 = AnyValue.loadFromProperties(prop2); + //System.out.println(conf2); + + //System.out.println(conf.copy().merge(conf2)); + //System.out.println(conf); + } }