cn.hutool.core.lang.Dict Maven / Gradle / Ivy
package cn.hutool.core.lang;
import cn.hutool.core.bean.BeanPath;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.getter.BasicTypeGetter;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.func.LambdaUtil;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
/**
* 字典对象,扩充了HashMap中的方法
*
* @author loolly
*/
public class Dict extends LinkedHashMap implements BasicTypeGetter {
private static final long serialVersionUID = 6135423866861206530L;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* 是否大小写不敏感
*/
private boolean caseInsensitive;
// --------------------------------------------------------------- Static method start
/**
* 创建Dict
*
* @return Dict
*/
public static Dict create() {
return new Dict();
}
/**
* 将PO对象转为Dict
*
* @param Bean类型
* @param bean Bean对象
* @return Vo
*/
public static Dict parse(T bean) {
return create().parseBean(bean);
}
/**
* 根据给定的Pair数组创建Dict对象
*
* @param pairs 键值对
* @return Dict
* @since 5.4.1
*/
@SafeVarargs
public static Dict of(Pair... pairs) {
final Dict dict = create();
for (Pair pair : pairs) {
dict.put(pair.getKey(), pair.getValue());
}
return dict;
}
/**
* 根据给定的键值对数组创建Dict对象,传入参数必须为key,value,key,value...
*
* 奇数参数必须为key,key最后会转换为String类型。
* 偶数参数必须为value,可以为任意类型。
*
*
* Dict dict = Dict.of(
* "RED", "#FF0000",
* "GREEN", "#00FF00",
* "BLUE", "#0000FF"
* );
*
*
* @param keysAndValues 键值对列表,必须奇数参数为key,偶数参数为value
* @return Dict
* @since 5.4.1
*/
public static Dict of(Object... keysAndValues) {
final Dict dict = create();
String key = null;
for (int i = 0; i < keysAndValues.length; i++) {
if (i % 2 == 0) {
key = Convert.toStr(keysAndValues[i]);
} else {
dict.put(key, keysAndValues[i]);
}
}
return dict;
}
// --------------------------------------------------------------- Static method end
// --------------------------------------------------------------- Constructor start
/**
* 构造
*/
public Dict() {
this(false);
}
/**
* 构造
*
* @param caseInsensitive 是否大小写不敏感
*/
public Dict(boolean caseInsensitive) {
this(DEFAULT_INITIAL_CAPACITY, caseInsensitive);
}
/**
* 构造
*
* @param initialCapacity 初始容量
*/
public Dict(int initialCapacity) {
this(initialCapacity, false);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param caseInsensitive 是否大小写不敏感
*/
public Dict(int initialCapacity, boolean caseInsensitive) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, caseInsensitive);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param loadFactor 容量增长因子,0~1,即达到容量的百分之多少时扩容
*/
public Dict(int initialCapacity, float loadFactor) {
this(initialCapacity, loadFactor, false);
}
/**
* 构造
*
* @param initialCapacity 初始容量
* @param loadFactor 容量增长因子,0~1,即达到容量的百分之多少时扩容
* @param caseInsensitive 是否大小写不敏感
* @since 4.5.16
*/
public Dict(int initialCapacity, float loadFactor, boolean caseInsensitive) {
super(initialCapacity, loadFactor);
this.caseInsensitive = caseInsensitive;
}
/**
* 构造
*
* @param m Map
*/
public Dict(Map m) {
super((null == m) ? new HashMap<>() : m);
}
// --------------------------------------------------------------- Constructor end
/**
* 转换为Bean对象
*
* @param Bean类型
* @param bean Bean
* @return Bean
*/
public T toBean(T bean) {
return toBean(bean, false);
}
/**
* 转换为Bean对象
*
* @param Bean类型
* @param bean Bean
* @return Bean
* @since 3.3.1
*/
public T toBeanIgnoreCase(T bean) {
BeanUtil.fillBeanWithMapIgnoreCase(this, bean, false);
return bean;
}
/**
* 转换为Bean对象
*
* @param Bean类型
* @param bean Bean
* @param isToCamelCase 是否转换为驼峰模式
* @return Bean
*/
public T toBean(T bean, boolean isToCamelCase) {
BeanUtil.fillBeanWithMap(this, bean, isToCamelCase, false);
return bean;
}
/**
* 转换为Bean对象,并使用驼峰法模式转换
*
* @param Bean类型
* @param bean Bean
* @return Bean
*/
public T toBeanWithCamelCase(T bean) {
BeanUtil.fillBeanWithMap(this, bean, true, false);
return bean;
}
/**
* 填充Value Object对象
*
* @param Bean类型
* @param clazz Value Object(或者POJO)的类
* @return vo
*/
public T toBean(Class clazz) {
return BeanUtil.toBean(this, clazz);
}
/**
* 填充Value Object对象,忽略大小写
*
* @param Bean类型
* @param clazz Value Object(或者POJO)的类
* @return vo
*/
public T toBeanIgnoreCase(Class clazz) {
return BeanUtil.toBeanIgnoreCase(this, clazz, false);
}
/**
* 将值对象转换为Dict
* 类名会被当作表名,小写第一个字母
*
* @param Bean类型
* @param bean 值对象
* @return 自己
*/
public Dict parseBean(T bean) {
Assert.notNull(bean, "Bean class must be not null");
this.putAll(BeanUtil.beanToMap(bean));
return this;
}
/**
* 将值对象转换为Dict
* 类名会被当作表名,小写第一个字母
*
* @param Bean类型
* @param bean 值对象
* @param isToUnderlineCase 是否转换为下划线模式
* @param ignoreNullValue 是否忽略值为空的字段
* @return 自己
*/
public Dict parseBean(T bean, boolean isToUnderlineCase, boolean ignoreNullValue) {
Assert.notNull(bean, "Bean class must be not null");
this.putAll(BeanUtil.beanToMap(bean, isToUnderlineCase, ignoreNullValue));
return this;
}
/**
* 与给定实体对比并去除相同的部分
* 此方法用于在更新操作时避免所有字段被更新,跳过不需要更新的字段 version from 2.0.0
*
* @param 字典对象类型
* @param dict 字典对象
* @param withoutNames 不需要去除的字段名
*/
public void removeEqual(T dict, String... withoutNames) {
HashSet withoutSet = CollUtil.newHashSet(withoutNames);
for (Map.Entry entry : dict.entrySet()) {
if (withoutSet.contains(entry.getKey())) {
continue;
}
final Object value = this.get(entry.getKey());
if (Objects.equals(value, entry.getValue())) {
this.remove(entry.getKey());
}
}
}
/**
* 过滤Map保留指定键值对,如果键不存在跳过
*
* @param keys 键列表
* @return Dict 结果
* @since 4.0.10
*/
public Dict filter(String... keys) {
final Dict result = new Dict(keys.length, 1);
for (String key : keys) {
if (this.containsKey(key)) {
result.put(key, this.get(key));
}
}
return result;
}
// -------------------------------------------------------------------- Set start
/**
* 设置列
*
* @param attr 属性
* @param value 值
* @return 本身
*/
public Dict set(String attr, Object value) {
this.put(attr, value);
return this;
}
/**
* 设置列,当键或值为null时忽略
*
* @param attr 属性
* @param value 值
* @return 本身
*/
public Dict setIgnoreNull(String attr, Object value) {
if (null != attr && null != value) {
set(attr, value);
}
return this;
}
// -------------------------------------------------------------------- Set end
// -------------------------------------------------------------------- Get start
@Override
public Object getObj(String key) {
return super.get(key);
}
/**
* 获得特定类型值
*
* @param 值类型
* @param attr 字段名
* @return 字段值
* @since 4.6.3
*/
public T getBean(String attr) {
return get(attr, null);
}
/**
* 获得特定类型值
*
* @param 值类型
* @param attr 字段名
* @param defaultValue 默认值
* @return 字段值
*/
@SuppressWarnings("unchecked")
public T get(String attr, T defaultValue) {
final Object result = get(attr);
return (T) (result != null ? result : defaultValue);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public String getStr(String attr) {
return Convert.toStr(get(attr), null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public Integer getInt(String attr) {
return Convert.toInt(get(attr), null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public Long getLong(String attr) {
return Convert.toLong(get(attr), null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public Float getFloat(String attr) {
return Convert.toFloat(get(attr), null);
}
@Override
public Short getShort(String attr) {
return Convert.toShort(get(attr), null);
}
@Override
public Character getChar(String attr) {
return Convert.toChar(get(attr), null);
}
@Override
public Double getDouble(String attr) {
return Convert.toDouble(get(attr), null);
}
@Override
public Byte getByte(String attr) {
return Convert.toByte(get(attr), null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public Boolean getBool(String attr) {
return Convert.toBool(get(attr), null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public BigDecimal getBigDecimal(String attr) {
return Convert.toBigDecimal(get(attr));
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public BigInteger getBigInteger(String attr) {
return Convert.toBigInteger(get(attr));
}
@Override
public > E getEnum(Class clazz, String key) {
return Convert.toEnum(clazz, get(key));
}
/**
* @param attr 字段名
* @return 字段值
*/
public byte[] getBytes(String attr) {
return get(attr, null);
}
/**
* @param attr 字段名
* @return 字段值
*/
@Override
public Date getDate(String attr) {
return get(attr, null);
}
/**
* @param attr 字段名
* @return 字段值
*/
public Time getTime(String attr) {
return get(attr, null);
}
/**
* @param attr 字段名
* @return 字段值
*/
public Timestamp getTimestamp(String attr) {
return get(attr, null);
}
/**
* @param attr 字段名
* @return 字段值
*/
public Number getNumber(String attr) {
return get(attr, null);
}
/**
* 通过表达式获取JSON中嵌套的对象
*
* - .表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值
* - []表达式,可以获取集合等对象中对应index的值
*
*
* 表达式栗子:
*
*
* persion
* persion.name
* persons[3]
* person.friends[5].name
*
*
* @param 目标类型
* @param expression 表达式
* @return 对象
* @see BeanPath#get(Object)
* @since 5.7.14
*/
@SuppressWarnings("unchecked")
public T getByPath(String expression) {
return (T) BeanPath.create(expression).get(this);
}
/**
* 通过表达式获取JSON中嵌套的对象
*
* - .表达式,可以获取Bean对象中的属性(字段)值或者Map中key对应的值
* - []表达式,可以获取集合等对象中对应index的值
*
*
* 表达式栗子:
*
*
* persion
* persion.name
* persons[3]
* person.friends[5].name
*
*
* 获取表达式对应值后转换为对应类型的值
*
* @param 返回值类型
* @param expression 表达式
* @param resultType 返回值类型
* @return 对象
* @see BeanPath#get(Object)
* @since 5.7.14
*/
public T getByPath(String expression, Class resultType) {
return Convert.convert(resultType, getByPath(expression));
}
// -------------------------------------------------------------------- Get end
@Override
public boolean containsKey(Object key) {
return super.containsKey(customKey((String) key));
}
@Override
public Object get(Object key) {
return super.get(customKey((String) key));
}
@Override
public Object put(String key, Object value) {
return super.put(customKey(key), value);
}
@Override
public void putAll(Map extends String, ?> m) {
m.forEach(this::put);
}
@Override
public Dict clone() {
return (Dict) super.clone();
}
@Override
public Object remove(Object key) {
return super.remove(customKey((String) key));
}
@Override
public boolean remove(Object key, Object value) {
return super.remove(customKey((String) key), value);
}
@Override
public boolean replace(String key, Object oldValue, Object newValue) {
return super.replace(customKey(key), oldValue, newValue);
}
@Override
public Object replace(String key, Object value) {
return super.replace(customKey(key), value);
}
//---------------------------------------------------------------------------- Override default methods start
@Override
public Object getOrDefault(Object key, Object defaultValue) {
return super.getOrDefault(customKey((String) key), defaultValue);
}
@Override
public Object computeIfPresent(final String key, final BiFunction super String, ? super Object, ?> remappingFunction) {
return super.computeIfPresent(customKey(key), remappingFunction);
}
@Override
public Object compute(final String key, final BiFunction super String, ? super Object, ?> remappingFunction) {
return super.compute(customKey(key), remappingFunction);
}
@Override
public Object merge(final String key, final Object value, final BiFunction super Object, ? super Object, ?> remappingFunction) {
return super.merge(customKey(key), value, remappingFunction);
}
@Override
public Object putIfAbsent(String key, Object value) {
return super.putIfAbsent(customKey(key), value);
}
@Override
public Object computeIfAbsent(String key, Function super String, ?> mappingFunction) {
return super.computeIfAbsent(customKey(key), mappingFunction);
}
//---------------------------------------------------------------------------- Override default methods end
/**
* 将Key转为小写
*
* @param key KEY
* @return 小写KEY
*/
private String customKey(String key) {
if (this.caseInsensitive && null != key) {
key = key.toLowerCase();
}
return key;
}
/**
* 通过lambda批量设置值
* 实际使用时,可以使用getXXX的方法引用来完成键值对的赋值:
*
* User user = GenericBuilder.of(User::new).with(User::setUsername, "hutool").build();
* Dict.create().setFields(user::getNickname, user::getUsername);
*
*
* @param fields lambda,不能为空
* @return this
* @since 5.7.23
*/
public Dict setFields(Func0>... fields) {
Arrays.stream(fields).forEach(f -> set(LambdaUtil.getFieldName(f), f.callWithRuntimeException()));
return this;
}
}