AnyValue增加copy和merge方法
This commit is contained in:
@@ -54,6 +54,8 @@ public abstract class AnyValue {
|
||||
|
||||
private Entry<DefaultAnyValue>[] 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<String> 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<DefaultAnyValue> 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<String> en : node.stringEntrys) {
|
||||
if (en == null) continue;
|
||||
setValue(en.name, en.value);
|
||||
}
|
||||
}
|
||||
if (node.anyEntrys != null) {
|
||||
for (Entry<DefaultAnyValue> 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<String>[] strings = av.getStringEntrys();
|
||||
if (strings == null) return this;
|
||||
for (Entry<String> 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<String> 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<DefaultAnyValue> en : this.anyEntrys) {
|
||||
@@ -419,6 +495,14 @@ public abstract class AnyValue {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean existsValue(String name) {
|
||||
for (Entry<String> 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<AnyValue, String, CharSequence> 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<String> en : getStringEntrys()) {
|
||||
sb.append(space).append(" '").append(en.name).append("': '").append(en.value).append("',\r\n");
|
||||
}
|
||||
for (Entry<AnyValue> 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);
|
||||
|
||||
/**
|
||||
* 回调子节点
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user