增加Kv工具类及测试代码

This commit is contained in:
aoshiguchen
2023-03-01 18:14:56 +08:00
parent 251b4c660a
commit a9f04eb785
2 changed files with 270 additions and 0 deletions
@@ -0,0 +1,221 @@
package fun.asgc.neutrino.core.base;
import java.io.Serializable;
import java.util.*;
/**
* 用于统一参数配置
* 1、有序性(适用于方法参数)
* 2、key为String类型时,忽略大小写、忽略分隔符(_、-),兼容启动命令传参 + 配置文件传参
* 3、父级委托机制:如果存在父级,且当前实例查不到,则委托父级查找。(适用于配置优先级:启动参数 > 配置文件 > 默认值)
* @author: aoshiguchen
* @date: 2023/3/1
*/
public class Kv<K,V> implements Map<K,V> , Serializable, Cloneable {
private LinkedHashMap<K, V> _m;
private HashMap<K, K> _k;
private Locale locale;
private String SEPARATOR = "_|-";
private Kv<K,V> parent;
private Kv() {
this(null, 16, null);
}
private Kv(Kv<K,V> parent) {
this(parent, 16, null);
}
public static <K,V> Kv<K,V> of() {
return new Kv<>();
}
public static <K,V> Kv<K,V> of(Kv<K,V> parent) {
return new Kv(parent);
}
public Kv(Kv<K,V> parent, int initialCapacity, Locale locale) {
this.parent = parent;
this._m = new LinkedHashMap<K, V>(initialCapacity) {
@Override
public boolean containsKey(Object key) {
return Kv.this.containsKey(key);
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
boolean doRemove = Kv.this.removeEldestEntry(eldest);
if (doRemove) {
if (eldest.getKey() instanceof String) {
_k.remove(convertKey((String) eldest.getKey()));
} else {
_k.remove(eldest.getKey());
}
}
return doRemove;
}
};
this._k = new HashMap<>(initialCapacity);
this.locale = (locale != null ? locale : Locale.getDefault());
}
@Override
public int size() {
return this._m.size();
}
public int stackSize() {
return this._m.size() + (null == parent ? 0 : parent.stackSize());
}
@Override
public boolean isEmpty() {
return this._m.isEmpty();
}
public boolean isStackEmpty() {
boolean res = this._m.isEmpty();
if (res && null != parent) {
res = parent.isStackEmpty();
}
return res;
}
@Override
public boolean containsKey(Object key) {
boolean convertKey = false;
if (key instanceof String) {
convertKey = this._k.containsKey(convertKey((String) key));
} else {
convertKey = this._k.containsKey(key);
}
return convertKey;
}
public boolean stackContainsKey(K k) {
return this.containsKey(k) || (null != parent && parent.containsKey(k));
}
@Override
public boolean containsValue(Object value) {
return this._m.containsValue(value);
}
public boolean stackContainsValue(Object value) {
return this.containsValue(value) || (null != parent && parent.containsValue(value));
}
@Override
public V get(Object key) {
K k = null;
try {
k = (K) key;
} catch (Exception e) {
return null;
}
if (k instanceof String) {
k = this._k.get(convertKey((String) k));
}
if (null != k) {
return this._m.get(k);
}
return null;
}
public V stackGet(K k) {
V res = get(k);
if (null == res && null != parent) {
res = parent.stackGet(k);
}
return res;
}
@Override
public V put(K key, V value) {
K k = key;
if (null != k && k instanceof String) {
k = (K) convertKey((String) key);
}
K oldKey = this._k.put(k, key);
if (null != oldKey && !oldKey.equals(key)) {
this._m.remove(oldKey);
}
return this._m.put(key, value);
}
@Override
public V remove(Object key) {
K k1 = null;
try {
k1 = (K) key;
} catch (Exception e) {
return null;
}
K k2 = null;
if (k1 instanceof String) {
k1 = (K) convertKey((String) k1);
k2 = this._k.remove(k1);
} else {
k2 = this._k.remove(k1);
}
if (null != k2) {
return this._m.remove(k2);
}
return null;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (m.isEmpty()) {
return;
}
m.forEach(this::put);
}
@Override
public void clear() {
this._k.clear();
this._m.clear();
}
@Override
public Set<K> keySet() {
return this._m.keySet();
}
@Override
public Collection<V> values() {
return this._m.values();
}
@Override
public Set<Entry<K, V>> entrySet() {
return this._m.entrySet();
}
public Locale getLocale() {
return this.locale;
}
protected String convertKey(String key) {
return key.toLowerCase(getLocale()).replaceAll(SEPARATOR, "");
}
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return false;
}
@Override
protected Kv<K,V> clone() {
Kv<K,V> res = new Kv<>();
if (null != parent) {
res.parent = parent.clone();
}
res._m = (LinkedHashMap<K, V>) _m.clone();
res._k = (HashMap<K, K>) _k.clone();
res.locale = locale;
return res;
}
}
@@ -0,0 +1,49 @@
package fun.asgc.neutrino.core.base;
import org.junit.Assert;
import org.junit.Test;
/**
* @author: aoshiguchen
* @date: 2023/3/1
*/
public class KvTest {
@Test
public void test1() {
Kv<String, Object> kv1 = Kv.of();
kv1.put("app.server.http.http-port", 8080);
kv1.put("app.server.http.jks_Path", "/123/456");
Kv<String, Object> kv2 = Kv.of(kv1);
kv2.put("app.server.http.httpPort", 8081);
kv2.put("app.server.http.context-path", "/");
Kv<String, Object> kv3 = Kv.of(kv2);
Assert.assertTrue(!kv1.isEmpty());
Assert.assertTrue(kv1.size() == 2);
Assert.assertTrue(kv1.stackSize() == 2);
Assert.assertTrue(kv1.get("app.server.http.http-port").equals(8080));
Assert.assertTrue(kv1.get("app.server.http.httpPort").equals(8080));
Assert.assertTrue(kv1.get("app.server.http.jks_Path").equals("/123/456"));
Assert.assertTrue(kv1.get("app.server.http.jksPath").equals("/123/456"));
Assert.assertTrue(!kv2.isEmpty());
Assert.assertTrue(kv2.size() == 2);
Assert.assertTrue(kv2.stackSize() == 4);
Assert.assertTrue(kv2.get("app.server.http.http-port").equals(8081));
Assert.assertTrue(kv2.get("app.server.http.httpPort").equals(8081));
Assert.assertTrue(kv2.get("app.server.http.jks-path") == null);
Assert.assertTrue(kv2.get("app.server.http.jksPath") == null);
Assert.assertTrue(kv2.get("app.server.http.context-path").equals("/"));
Assert.assertTrue(kv2.stackGet("app.server.http.jks-path").equals("/123/456"));
Assert.assertTrue(kv2.stackGet("app.server.http.jksPath").equals("/123/456"));
Assert.assertTrue(kv2.stackGet("app.server.http.context-path").equals("/"));
Assert.assertTrue(kv3.isEmpty());
Assert.assertTrue(!kv3.isStackEmpty());
Assert.assertTrue(kv3.size() == 0);
Assert.assertTrue(kv3.stackSize() == 4);
}
}