This commit is contained in:
Looly 2022-03-06 21:01:08 +08:00
parent 4b22f7cc74
commit 1e113ef83f
12 changed files with 75 additions and 104 deletions

View File

@ -225,8 +225,8 @@ public class BeanUtil {
*/ */
private static Map<String, PropertyDescriptor> internalGetPropertyDescriptorMap(Class<?> clazz, boolean ignoreCase) throws BeanException { private static Map<String, PropertyDescriptor> internalGetPropertyDescriptorMap(Class<?> clazz, boolean ignoreCase) throws BeanException {
final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz); final PropertyDescriptor[] propertyDescriptors = getPropertyDescriptors(clazz);
final Map<String, PropertyDescriptor> map = ignoreCase ? new CaseInsensitiveMap<>(propertyDescriptors.length, 1) final Map<String, PropertyDescriptor> map = ignoreCase ? new CaseInsensitiveMap<>(propertyDescriptors.length, 1f)
: new HashMap<>((int) (propertyDescriptors.length), 1); : new HashMap<>(propertyDescriptors.length, 1);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) { for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
map.put(propertyDescriptor.getName(), propertyDescriptor); map.put(propertyDescriptor.getName(), propertyDescriptor);

View File

@ -1,7 +1,5 @@
package cn.hutool.core.map; package cn.hutool.core.map;
import cn.hutool.core.util.StrUtil;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -15,7 +13,7 @@ import java.util.Map;
* @param <V> 值类型 * @param <V> 值类型
* @since 4.0.7 * @since 4.0.7
*/ */
public class CamelCaseLinkedMap<K, V> extends CustomKeyMap<K, V> { public class CamelCaseLinkedMap<K, V> extends CamelCaseMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
@ -48,7 +46,7 @@ public class CamelCaseLinkedMap<K, V> extends CustomKeyMap<K, V> {
* 构造 * 构造
* *
* @param loadFactor 加载因子 * @param loadFactor 加载因子
* @param m Map * @param m Map数据会被默认拷贝到一个新的LinkedHashMap中
*/ */
public CamelCaseLinkedMap(float loadFactor, Map<? extends K, ? extends V> m) { public CamelCaseLinkedMap(float loadFactor, Map<? extends K, ? extends V> m) {
this(m.size(), loadFactor); this(m.size(), loadFactor);
@ -65,18 +63,4 @@ public class CamelCaseLinkedMap<K, V> extends CustomKeyMap<K, V> {
super(new LinkedHashMap<>(initialCapacity, loadFactor)); super(new LinkedHashMap<>(initialCapacity, loadFactor));
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为驼峰风格如果key为字符串的话
*
* @param key KEY
* @return 驼峰Key
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = StrUtil.toCamelCase(key.toString());
}
return key;
}
} }

View File

@ -1,24 +1,24 @@
package cn.hutool.core.map; package cn.hutool.core.map;
import cn.hutool.core.util.StrUtil;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import cn.hutool.core.util.StrUtil;
/** /**
* 驼峰Key风格的Map<br> * 驼峰Key风格的Map<br>
* 对KEY转换为驼峰get("int_value")和get("intValue")获得的值相同put进入的值也会被覆盖 * 对KEY转换为驼峰get("int_value")和get("intValue")获得的值相同put进入的值也会被覆盖
* *
* @author Looly
*
* @param <K> 键类型 * @param <K> 键类型
* @param <V> 值类型 * @param <V> 值类型
* @author Looly
* @since 4.0.7 * @since 4.0.7
*/ */
public class CamelCaseMap<K, V> extends CustomKeyMap<K, V> { public class CamelCaseMap<K, V> extends FuncKeyMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
/** /**
* 构造 * 构造
*/ */
@ -48,7 +48,7 @@ public class CamelCaseMap<K, V> extends CustomKeyMap<K, V> {
* 构造 * 构造
* *
* @param loadFactor 加载因子 * @param loadFactor 加载因子
* @param m Map * @param m 初始Map数据会被默认拷贝到一个新的HashMap中
*/ */
public CamelCaseMap(float loadFactor, Map<? extends K, ? extends V> m) { public CamelCaseMap(float loadFactor, Map<? extends K, ? extends V> m) {
this(m.size(), loadFactor); this(m.size(), loadFactor);
@ -59,24 +59,26 @@ public class CamelCaseMap<K, V> extends CustomKeyMap<K, V> {
* 构造 * 构造
* *
* @param initialCapacity 初始大小 * @param initialCapacity 初始大小
* @param loadFactor 加载因子 * @param loadFactor 加载因子
*/ */
public CamelCaseMap(int initialCapacity, float loadFactor) { public CamelCaseMap(int initialCapacity, float loadFactor) {
super(new HashMap<>(initialCapacity, loadFactor)); this(MapBuilder.create(new HashMap<>(initialCapacity, loadFactor)));
} }
// ------------------------------------------------------------------------- Constructor end
/** /**
* 将Key转为驼峰风格如果key为字符串的话 * 构造<br>
* 注意此构造将传入的Map作为被包装的Map针对任何修改传入的Map都会被同样修改
* *
* @param key KEY * @param emptyMapBuilder Map构造器必须构造空的Map
* @return 驼峰Key
*/ */
@Override CamelCaseMap(MapBuilder<K, V> emptyMapBuilder) {
protected Object customKey(Object key) { super(emptyMapBuilder.build(), (key) -> {
if (key instanceof CharSequence) { if (key instanceof CharSequence) {
key = StrUtil.toCamelCase(key.toString()); key = StrUtil.toCamelCase(key.toString());
} }
return key; //noinspection unchecked
return (K) key;
});
} }
// ------------------------------------------------------------------------- Constructor end
} }

View File

@ -13,7 +13,7 @@ import java.util.Map;
* @param <V> 值类型 * @param <V> 值类型
* @since 3.3.1 * @since 3.3.1
*/ */
public class CaseInsensitiveLinkedMap<K, V> extends CustomKeyMap<K, V> { public class CaseInsensitiveLinkedMap<K, V> extends CaseInsensitiveMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
@ -64,18 +64,4 @@ public class CaseInsensitiveLinkedMap<K, V> extends CustomKeyMap<K, V> {
super(new LinkedHashMap<>(initialCapacity, loadFactor)); super(new LinkedHashMap<>(initialCapacity, loadFactor));
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为小写
*
* @param key KEY
* @return 小写KEY
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = key.toString().toLowerCase();
}
return key;
}
} }

View File

@ -13,7 +13,7 @@ import java.util.Map;
* @param <V> 值类型 * @param <V> 值类型
* @since 3.0.2 * @since 3.0.2
*/ */
public class CaseInsensitiveMap<K, V> extends CustomKeyMap<K, V> { public class CaseInsensitiveMap<K, V> extends FuncKeyMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
//------------------------------------------------------------------------- Constructor start //------------------------------------------------------------------------- Constructor start
@ -34,9 +34,10 @@ public class CaseInsensitiveMap<K, V> extends CustomKeyMap<K, V> {
} }
/** /**
* 构造 * 构造<br>
* 注意此构造将传入的Map作为被包装的Map针对任何修改传入的Map都会被同样修改
* *
* @param m Map * @param m 被包装的自定义Map创建器
*/ */
public CaseInsensitiveMap(Map<? extends K, ? extends V> m) { public CaseInsensitiveMap(Map<? extends K, ? extends V> m) {
this(DEFAULT_LOAD_FACTOR, m); this(DEFAULT_LOAD_FACTOR, m);
@ -61,21 +62,23 @@ public class CaseInsensitiveMap<K, V> extends CustomKeyMap<K, V> {
* @param loadFactor 加载因子 * @param loadFactor 加载因子
*/ */
public CaseInsensitiveMap(int initialCapacity, float loadFactor) { public CaseInsensitiveMap(int initialCapacity, float loadFactor) {
super(new HashMap<>(initialCapacity, loadFactor)); this(MapBuilder.create(new HashMap<>(initialCapacity, loadFactor)));
} }
//------------------------------------------------------------------------- Constructor end
/** /**
* 将Key转为小写 * 构造<br>
* 注意此构造将传入的Map作为被包装的Map针对任何修改传入的Map都会被同样修改
* *
* @param key KEY * @param emptyMapBuilder 被包装的自定义Map创建器
* @return 小写KEY
*/ */
@Override CaseInsensitiveMap(MapBuilder<K, V> emptyMapBuilder) {
protected Object customKey(Object key) { super(emptyMapBuilder.build(), (key)->{
if (key instanceof CharSequence) { if (key instanceof CharSequence) {
key = key.toString().toLowerCase(); key = key.toString().toLowerCase();
} }
return key; //noinspection unchecked
return (K) key;
});
} }
//------------------------------------------------------------------------- Constructor end
} }

View File

@ -15,7 +15,7 @@ import java.util.TreeMap;
* @param <V> 值类型 * @param <V> 值类型
* @since 3.3.1 * @since 3.3.1
*/ */
public class CaseInsensitiveTreeMap<K, V> extends CustomKeyMap<K, V> { public class CaseInsensitiveTreeMap<K, V> extends CaseInsensitiveMap<K, V> {
private static final long serialVersionUID = 4043263744224569870L; private static final long serialVersionUID = 4043263744224569870L;
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
@ -40,7 +40,7 @@ public class CaseInsensitiveTreeMap<K, V> extends CustomKeyMap<K, V> {
/** /**
* 构造 * 构造
* *
* @param m Map * @param m Map初始Map键值对会被复制到新的TreeMap中
* @since 3.1.2 * @since 3.1.2
*/ */
public CaseInsensitiveTreeMap(SortedMap<? extends K, ? extends V> m) { public CaseInsensitiveTreeMap(SortedMap<? extends K, ? extends V> m) {
@ -56,18 +56,4 @@ public class CaseInsensitiveTreeMap<K, V> extends CustomKeyMap<K, V> {
super(new TreeMap<>(comparator)); super(new TreeMap<>(comparator));
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end
/**
* 将Key转为小写
*
* @param key KEY
* @return 小写KEY
*/
@Override
protected Object customKey(Object key) {
if (key instanceof CharSequence) {
key = key.toString().toLowerCase();
}
return key;
}
} }

View File

@ -18,11 +18,11 @@ public abstract class CustomKeyMap<K, V> extends MapWrapper<K, V> {
* 构造<br> * 构造<br>
* 通过传入一个Map从而确定Map的类型子类需创建一个空的Map而非传入一个已有Map否则值可能会被修改 * 通过传入一个Map从而确定Map的类型子类需创建一个空的Map而非传入一个已有Map否则值可能会被修改
* *
* @param m Map 被包装的Map * @param emptyMap Map 被包装的Map必须为空Map否则自定义key会无效
* @since 3.1.2 * @since 3.1.2
*/ */
public CustomKeyMap(Map<K, V> m) { public CustomKeyMap(Map<K, V> emptyMap) {
super(m); super(emptyMap);
} }
@Override @Override

View File

@ -3,7 +3,8 @@ package cn.hutool.core.map;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
/** /**
* 固定大小的{@link LinkedHashMap} 实现 * 固定大小的{@link LinkedHashMap} 实现<br>
* 注意此类非线程安全由于{@link #get(Object)}操作会修改链表的顺序结构因此也不可以使用读写锁
* *
* @author looly * @author looly
* *

View File

@ -19,13 +19,14 @@ public class FuncKeyMap<K, V> extends CustomKeyMap<K, V> {
// ------------------------------------------------------------------------- Constructor start // ------------------------------------------------------------------------- Constructor start
/** /**
* 构造 * 构造<br>
* 注意提供的Map中不能有键值对否则可能导致自定义key失效
* *
* @param m Map * @param emptyMap Map提供的空map
* @param keyFunc 自定义KEY的函数 * @param keyFunc 自定义KEY的函数
*/ */
public FuncKeyMap(Map<K, V> m, Function<Object, K> keyFunc) { public FuncKeyMap(Map<K, V> emptyMap, Function<Object, K> keyFunc) {
super(m); super(emptyMap);
this.keyFunc = keyFunc; this.keyFunc = keyFunc;
} }
// ------------------------------------------------------------------------- Constructor end // ------------------------------------------------------------------------- Constructor end

View File

@ -13,7 +13,7 @@ import java.util.function.Supplier;
* @param <V> Value类型 * @param <V> Value类型
* @since 3.1.1 * @since 3.1.1
*/ */
public class MapBuilder<K, V> implements Builder<Map<K,V>> { public class MapBuilder<K, V> implements Builder<Map<K, V>> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final Map<K, V> map; private final Map<K, V> map;
@ -120,6 +120,17 @@ public class MapBuilder<K, V> implements Builder<Map<K,V>> {
return this; return this;
} }
/**
* 清空Map
*
* @return this
* @since 5.7.23
*/
public MapBuilder<K, V> clear() {
this.map.clear();
return this;
}
/** /**
* 创建后的map * 创建后的map
* *

View File

@ -88,7 +88,6 @@ public class MapWrapper<K, V> implements Map<K, V>, Iterable<Map.Entry<K, V>>, S
} }
@Override @Override
@SuppressWarnings("NullableProblems")
public void putAll(Map<? extends K, ? extends V> m) { public void putAll(Map<? extends K, ? extends V> m) {
raw.putAll(m); raw.putAll(m);
} }
@ -99,25 +98,21 @@ public class MapWrapper<K, V> implements Map<K, V>, Iterable<Map.Entry<K, V>>, S
} }
@Override @Override
@SuppressWarnings("NullableProblems")
public Collection<V> values() { public Collection<V> values() {
return raw.values(); return raw.values();
} }
@Override @Override
@SuppressWarnings("NullableProblems")
public Set<K> keySet() { public Set<K> keySet() {
return raw.keySet(); return raw.keySet();
} }
@Override @Override
@SuppressWarnings("NullableProblems")
public Set<Entry<K, V>> entrySet() { public Set<Entry<K, V>> entrySet() {
return raw.entrySet(); return raw.entrySet();
} }
@Override @Override
@SuppressWarnings("NullableProblems")
public Iterator<Entry<K, V>> iterator() { public Iterator<Entry<K, V>> iterator() {
return this.entrySet().iterator(); return this.entrySet().iterator();
} }

View File

@ -5,6 +5,7 @@ import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.bean.copier.ValueProvider; import cn.hutool.core.bean.copier.ValueProvider;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil; import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
@ -78,14 +79,15 @@ public class BeanUtilTest {
@Test @Test
public void fillBeanWithMapIgnoreCaseTest() { public void fillBeanWithMapIgnoreCaseTest() {
HashMap<String, Object> map = MapUtil.newHashMap(); Map<String, Object> map = MapBuilder.<String, Object>create()
map.put("Name", "Joe"); .put("Name", "Joe")
map.put("aGe", 12); .put("aGe", 12)
map.put("openId", "DFDFSDFWERWER"); .put("openId", "DFDFSDFWERWER")
.build();
SubPerson person = BeanUtil.fillBeanWithMapIgnoreCase(map, new SubPerson(), false); SubPerson person = BeanUtil.fillBeanWithMapIgnoreCase(map, new SubPerson(), false);
Assert.assertEquals(person.getName(), "Joe"); Assert.assertEquals("Joe", person.getName());
Assert.assertEquals(person.getAge(), 12); Assert.assertEquals(12, person.getAge());
Assert.assertEquals(person.getOpenid(), "DFDFSDFWERWER"); Assert.assertEquals("DFDFSDFWERWER", person.getOpenid());
} }
@Test @Test