mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add BeanMap
This commit is contained in:
parent
3a73d3d0a0
commit
e67f37fc2f
@ -25,6 +25,7 @@ import org.dromara.hutool.core.collection.set.SetUtil;
|
||||
import org.dromara.hutool.core.convert.ConvertUtil;
|
||||
import org.dromara.hutool.core.convert.impl.RecordConverter;
|
||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
||||
import org.dromara.hutool.core.map.BeanMap;
|
||||
import org.dromara.hutool.core.map.CaseInsensitiveMap;
|
||||
import org.dromara.hutool.core.map.Dict;
|
||||
import org.dromara.hutool.core.map.MapUtil;
|
||||
@ -297,6 +298,16 @@ public class BeanUtil {
|
||||
|
||||
// region ----- beanToMap
|
||||
|
||||
/**
|
||||
* 将Bean包装为Map形式
|
||||
* @param bean Bean
|
||||
* @return {@link BeanMap}
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public static Map<String, Object> toBeanMap(final Object bean) {
|
||||
return BeanMap.of(bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将bean的部分属性转换成map<br>
|
||||
* 可选拷贝哪些属性值,默认是不忽略值为{@code null}的值的。
|
||||
|
@ -62,7 +62,8 @@ public class ListNode implements Node{
|
||||
// 只支持String为key的Map
|
||||
return MapUtil.getAny((Map<String, ?>) bean, unWrappedNames);
|
||||
} else {
|
||||
final Map<String, Object> map = BeanUtil.beanToMap(bean);
|
||||
// 一次性使用,包装Bean避免无用转换
|
||||
final Map<String, Object> map = BeanUtil.toBeanMap(bean);
|
||||
return MapUtil.getAny(map, unWrappedNames);
|
||||
}
|
||||
}
|
||||
|
@ -84,16 +84,17 @@ public class EntryConverter implements MatcherConverter, Serializable {
|
||||
if (value instanceof Map.Entry) {
|
||||
final Map.Entry entry = (Map.Entry) value;
|
||||
map = MapUtil.of(entry.getKey(), entry.getValue());
|
||||
}else if (value instanceof Pair) {
|
||||
} else if (value instanceof Pair) {
|
||||
final Pair entry = (Pair<?, ?>) value;
|
||||
map = MapUtil.of(entry.getLeft(), entry.getRight());
|
||||
}else if (value instanceof Map) {
|
||||
} else if (value instanceof Map) {
|
||||
map = (Map) value;
|
||||
} else if (value instanceof CharSequence) {
|
||||
final CharSequence str = (CharSequence) value;
|
||||
map = strToMap(str);
|
||||
} else if (BeanUtil.isWritableBean(value.getClass())) {
|
||||
map = BeanUtil.beanToMap(value);
|
||||
// 一次性只读场景,包装为Map效率更高
|
||||
map = BeanUtil.toBeanMap(value);
|
||||
}
|
||||
|
||||
if (null != map) {
|
||||
@ -133,13 +134,14 @@ public class EntryConverter implements MatcherConverter, Serializable {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) {
|
||||
|
||||
Object key = null;
|
||||
Object value = null;
|
||||
final Object key;
|
||||
final Object value;
|
||||
if (1 == map.size()) {
|
||||
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
||||
key = entry.getKey();
|
||||
value = entry.getValue();
|
||||
} else if (2 == map.size()) {
|
||||
} else {
|
||||
// 忽略Map中其它属性
|
||||
key = map.get("key");
|
||||
value = map.get("value");
|
||||
}
|
||||
|
@ -84,7 +84,8 @@ public class PairConverter implements Converter {
|
||||
final CharSequence str = (CharSequence) value;
|
||||
map = strToMap(str);
|
||||
} else if (BeanUtil.isReadableBean(value.getClass())) {
|
||||
map = BeanUtil.beanToMap(value);
|
||||
// 一次性只读场景,包装为Map效率更高
|
||||
map = BeanUtil.toBeanMap(value);
|
||||
}
|
||||
|
||||
if (null != map) {
|
||||
@ -123,13 +124,14 @@ public class PairConverter implements Converter {
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static Pair<?, ?> mapToPair(final Type keyType, final Type valueType, final Map map) {
|
||||
|
||||
Object left = null;
|
||||
Object right = null;
|
||||
final Object left;
|
||||
final Object right;
|
||||
if (1 == map.size()) {
|
||||
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
||||
left = entry.getKey();
|
||||
right = entry.getValue();
|
||||
} else if (2 == map.size()) {
|
||||
} else {
|
||||
// 忽略Map中其它属性
|
||||
left = map.get("left");
|
||||
right = map.get("right");
|
||||
}
|
||||
|
@ -70,7 +70,8 @@ public class TripleConverter implements Converter {
|
||||
throws ConvertException {
|
||||
Map map = null;
|
||||
if (BeanUtil.isReadableBean(value.getClass())) {
|
||||
map = BeanUtil.beanToMap(value);
|
||||
// 一次性只读场景,包装为Map效率更高
|
||||
map = BeanUtil.toBeanMap(value);
|
||||
}
|
||||
|
||||
if (null != map) {
|
||||
|
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2024 Hutool Team and hutool.cn
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.dromara.hutool.core.map;
|
||||
|
||||
import org.dromara.hutool.core.bean.BeanUtil;
|
||||
import org.dromara.hutool.core.bean.PropDesc;
|
||||
import org.dromara.hutool.core.util.ObjUtil;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Bean的Map接口实现<br>
|
||||
* 通过反射方式,将一个Bean的操作转化为Map操作
|
||||
*
|
||||
* @author Looly
|
||||
* @since 6.0.0
|
||||
*/
|
||||
public class BeanMap implements Map<String, Object> {
|
||||
|
||||
/**
|
||||
* 构建BeanMap
|
||||
*
|
||||
* @param bean Bean
|
||||
* @return BeanMap
|
||||
*/
|
||||
public static BeanMap of(final Object bean) {
|
||||
return new BeanMap(bean);
|
||||
}
|
||||
|
||||
private final Object bean;
|
||||
private final Map<String, PropDesc> propDescMap;
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param bean Bean
|
||||
*/
|
||||
public BeanMap(final Object bean) {
|
||||
this.bean = bean;
|
||||
this.propDescMap = BeanUtil.getBeanDesc(bean.getClass()).getPropMap(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.propDescMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return propDescMap.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(final Object key) {
|
||||
return this.propDescMap.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(final Object value) {
|
||||
for (final PropDesc propDesc : this.propDescMap.values()) {
|
||||
if (ObjUtil.equals(propDesc.getValue(bean), value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(final Object key) {
|
||||
final PropDesc propDesc = this.propDescMap.get(key);
|
||||
if (null != propDesc) {
|
||||
return propDesc.getValue(bean);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object put(final String key, final Object value) {
|
||||
final PropDesc propDesc = this.propDescMap.get(key);
|
||||
if (null != propDesc) {
|
||||
final Object oldValue = propDesc.getValue(bean);
|
||||
propDesc.setValue(bean, value);
|
||||
return oldValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(final Object key) {
|
||||
throw new UnsupportedOperationException("Can not remove field for Bean!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(final Map<? extends String, ?> m) {
|
||||
m.forEach(this::put);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
throw new UnsupportedOperationException("Can not clear fields for Bean!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return this.propDescMap.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
final List<Object> list = new ArrayList<>(size());
|
||||
for (final PropDesc propDesc : this.propDescMap.values()) {
|
||||
list.add(propDesc.getValue(bean));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
final HashSet<Entry<String, Object>> set = new HashSet<>(size(), 1);
|
||||
this.propDescMap.forEach((key, propDesc) -> set.add(new AbstractMap.SimpleEntry<>(key, propDesc.getValue(bean))));
|
||||
return set;
|
||||
}
|
||||
}
|
@ -246,7 +246,8 @@ public class Dict extends CustomKeyMap<String, Object> implements TypeGetter<Str
|
||||
*/
|
||||
public <T> Dict parseBean(final T bean) {
|
||||
Assert.notNull(bean, "Bean must not be null");
|
||||
this.putAll(BeanUtil.beanToMap(bean));
|
||||
// 一次性使用,避免先生成Map,再复制造成空间浪费
|
||||
this.putAll(BeanUtil.toBeanMap(bean));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -209,6 +209,23 @@ public class BeanUtilTest {
|
||||
assertFalse(map.containsKey("SUBNAME"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toBeanMapTest() {
|
||||
final SubPerson person = new SubPerson();
|
||||
person.setAge(14);
|
||||
person.setOpenid("11213232");
|
||||
person.setName("测试A11");
|
||||
person.setSubName("sub名字");
|
||||
|
||||
final Map<String, Object> map = BeanUtil.toBeanMap(person);
|
||||
|
||||
assertEquals("测试A11", map.get("name"));
|
||||
assertEquals(14, map.get("age"));
|
||||
assertEquals("11213232", map.get("openid"));
|
||||
// static属性应被忽略
|
||||
assertFalse(map.containsKey("SUBNAME"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanToMapNullPropertiesTest() {
|
||||
final SubPerson person = new SubPerson();
|
||||
|
Loading…
x
Reference in New Issue
Block a user