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.ConvertUtil;
|
||||||
import org.dromara.hutool.core.convert.impl.RecordConverter;
|
import org.dromara.hutool.core.convert.impl.RecordConverter;
|
||||||
import org.dromara.hutool.core.lang.mutable.MutableEntry;
|
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.CaseInsensitiveMap;
|
||||||
import org.dromara.hutool.core.map.Dict;
|
import org.dromara.hutool.core.map.Dict;
|
||||||
import org.dromara.hutool.core.map.MapUtil;
|
import org.dromara.hutool.core.map.MapUtil;
|
||||||
@ -297,6 +298,16 @@ public class BeanUtil {
|
|||||||
|
|
||||||
// region ----- beanToMap
|
// 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>
|
* 将bean的部分属性转换成map<br>
|
||||||
* 可选拷贝哪些属性值,默认是不忽略值为{@code null}的值的。
|
* 可选拷贝哪些属性值,默认是不忽略值为{@code null}的值的。
|
||||||
|
@ -62,7 +62,8 @@ public class ListNode implements Node{
|
|||||||
// 只支持String为key的Map
|
// 只支持String为key的Map
|
||||||
return MapUtil.getAny((Map<String, ?>) bean, unWrappedNames);
|
return MapUtil.getAny((Map<String, ?>) bean, unWrappedNames);
|
||||||
} else {
|
} else {
|
||||||
final Map<String, Object> map = BeanUtil.beanToMap(bean);
|
// 一次性使用,包装Bean避免无用转换
|
||||||
|
final Map<String, Object> map = BeanUtil.toBeanMap(bean);
|
||||||
return MapUtil.getAny(map, unWrappedNames);
|
return MapUtil.getAny(map, unWrappedNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,16 +84,17 @@ public class EntryConverter implements MatcherConverter, Serializable {
|
|||||||
if (value instanceof Map.Entry) {
|
if (value instanceof Map.Entry) {
|
||||||
final Map.Entry entry = (Map.Entry) value;
|
final Map.Entry entry = (Map.Entry) value;
|
||||||
map = MapUtil.of(entry.getKey(), entry.getValue());
|
map = MapUtil.of(entry.getKey(), entry.getValue());
|
||||||
}else if (value instanceof Pair) {
|
} else if (value instanceof Pair) {
|
||||||
final Pair entry = (Pair<?, ?>) value;
|
final Pair entry = (Pair<?, ?>) value;
|
||||||
map = MapUtil.of(entry.getLeft(), entry.getRight());
|
map = MapUtil.of(entry.getLeft(), entry.getRight());
|
||||||
}else if (value instanceof Map) {
|
} else if (value instanceof Map) {
|
||||||
map = (Map) value;
|
map = (Map) value;
|
||||||
} else if (value instanceof CharSequence) {
|
} else if (value instanceof CharSequence) {
|
||||||
final CharSequence str = (CharSequence) value;
|
final CharSequence str = (CharSequence) value;
|
||||||
map = strToMap(str);
|
map = strToMap(str);
|
||||||
} else if (BeanUtil.isWritableBean(value.getClass())) {
|
} else if (BeanUtil.isWritableBean(value.getClass())) {
|
||||||
map = BeanUtil.beanToMap(value);
|
// 一次性只读场景,包装为Map效率更高
|
||||||
|
map = BeanUtil.toBeanMap(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != map) {
|
if (null != map) {
|
||||||
@ -133,13 +134,14 @@ public class EntryConverter implements MatcherConverter, Serializable {
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) {
|
private static Map.Entry<?, ?> mapToEntry(final Type targetType, final Type keyType, final Type valueType, final Map map) {
|
||||||
|
|
||||||
Object key = null;
|
final Object key;
|
||||||
Object value = null;
|
final Object value;
|
||||||
if (1 == map.size()) {
|
if (1 == map.size()) {
|
||||||
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
||||||
key = entry.getKey();
|
key = entry.getKey();
|
||||||
value = entry.getValue();
|
value = entry.getValue();
|
||||||
} else if (2 == map.size()) {
|
} else {
|
||||||
|
// 忽略Map中其它属性
|
||||||
key = map.get("key");
|
key = map.get("key");
|
||||||
value = map.get("value");
|
value = map.get("value");
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,8 @@ public class PairConverter implements Converter {
|
|||||||
final CharSequence str = (CharSequence) value;
|
final CharSequence str = (CharSequence) value;
|
||||||
map = strToMap(str);
|
map = strToMap(str);
|
||||||
} else if (BeanUtil.isReadableBean(value.getClass())) {
|
} else if (BeanUtil.isReadableBean(value.getClass())) {
|
||||||
map = BeanUtil.beanToMap(value);
|
// 一次性只读场景,包装为Map效率更高
|
||||||
|
map = BeanUtil.toBeanMap(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != map) {
|
if (null != map) {
|
||||||
@ -123,13 +124,14 @@ public class PairConverter implements Converter {
|
|||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private static Pair<?, ?> mapToPair(final Type keyType, final Type valueType, final Map map) {
|
private static Pair<?, ?> mapToPair(final Type keyType, final Type valueType, final Map map) {
|
||||||
|
|
||||||
Object left = null;
|
final Object left;
|
||||||
Object right = null;
|
final Object right;
|
||||||
if (1 == map.size()) {
|
if (1 == map.size()) {
|
||||||
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
final Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
|
||||||
left = entry.getKey();
|
left = entry.getKey();
|
||||||
right = entry.getValue();
|
right = entry.getValue();
|
||||||
} else if (2 == map.size()) {
|
} else {
|
||||||
|
// 忽略Map中其它属性
|
||||||
left = map.get("left");
|
left = map.get("left");
|
||||||
right = map.get("right");
|
right = map.get("right");
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,8 @@ public class TripleConverter implements Converter {
|
|||||||
throws ConvertException {
|
throws ConvertException {
|
||||||
Map map = null;
|
Map map = null;
|
||||||
if (BeanUtil.isReadableBean(value.getClass())) {
|
if (BeanUtil.isReadableBean(value.getClass())) {
|
||||||
map = BeanUtil.beanToMap(value);
|
// 一次性只读场景,包装为Map效率更高
|
||||||
|
map = BeanUtil.toBeanMap(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null != map) {
|
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) {
|
public <T> Dict parseBean(final T bean) {
|
||||||
Assert.notNull(bean, "Bean must not be null");
|
Assert.notNull(bean, "Bean must not be null");
|
||||||
this.putAll(BeanUtil.beanToMap(bean));
|
// 一次性使用,避免先生成Map,再复制造成空间浪费
|
||||||
|
this.putAll(BeanUtil.toBeanMap(bean));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +209,23 @@ public class BeanUtilTest {
|
|||||||
assertFalse(map.containsKey("SUBNAME"));
|
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
|
@Test
|
||||||
public void beanToMapNullPropertiesTest() {
|
public void beanToMapNullPropertiesTest() {
|
||||||
final SubPerson person = new SubPerson();
|
final SubPerson person = new SubPerson();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user