Browse Source

add toBean support Map

Looly 5 years ago
parent
commit
9ff2d650bb

+ 2 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-## 5.3.6 (2020-05-19)
+## 5.3.6 (2020-05-25)
 
 ### 新特性
 * 【core   】     NumberConverter Long类型增加日期转换(pr#872@Github)
@@ -14,6 +14,7 @@
 * 【core   】     ImgUtil增加toBase64DateUri,URLUtil增加getDataUri方法
 * 【core   】     IterUtil添加List转Map的工具方法(pr#123@Gitee)
 * 【core   】     BeanValuePovider转换失败时,返回原数据,而非null
+* 【core   】     支持BeanUtil.toBean(object, Map.class)转换(issue#I1I4HC@Gitee)
 
 ### Bug修复
 * 【core   】     修复SimpleCache死锁问题(issue#I1HOKB@Gitee)

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/bean/BeanUtil.java

@@ -476,7 +476,7 @@ public class BeanUtil {
 	 * @since 5.2.4
 	 */
 	public static <T> T toBean(Object source, Class<T> clazz, CopyOptions options) {
-		final T target = ReflectUtil.newInstance(clazz);
+		final T target = ReflectUtil.newInstanceIfPossible(clazz);
 		copyProperties(source, target, options);
 		return target;
 	}

+ 20 - 0
hutool-core/src/main/java/cn/hutool/core/util/ReflectUtil.java

@@ -13,6 +13,7 @@ import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -769,13 +770,32 @@ public class ReflectUtil {
 
 	/**
 	 * 尝试遍历并调用此类的所有构造方法,直到构造成功并返回
+	 * <p>
+	 * 对于某些特殊的接口,按照其默认实现实例化,例如:
+	 * <pre>
+	 *     Map       -》 HashMap
+	 *     Collction -》 ArrayList
+	 *     List      -》 ArrayList
+	 *     Set       -》 HashSet
+	 * </pre>
 	 *
 	 * @param <T>       对象类型
 	 * @param beanClass 被构造的类
 	 * @return 构造后的对象
 	 */
+	@SuppressWarnings("unchecked")
 	public static <T> T newInstanceIfPossible(Class<T> beanClass) {
 		Assert.notNull(beanClass);
+
+		// 某些特殊接口的实例化按照默认实现进行
+		if (beanClass.isAssignableFrom(AbstractMap.class)) {
+			beanClass = (Class<T>) HashMap.class;
+		} else if (beanClass.isAssignableFrom(List.class)) {
+			beanClass = (Class<T>) ArrayList.class;
+		} else if (beanClass.isAssignableFrom(Set.class)) {
+			beanClass = (Class<T>) HashSet.class;
+		}
+
 		try {
 			return newInstance(beanClass);
 		} catch (Exception e) {

+ 28 - 28
hutool-core/src/main/java/cn/hutool/core/util/StrUtil.java

@@ -1741,14 +1741,14 @@ public class StrUtil {
 	 * 如果分隔字符串为空串"",则返回空串,如果分隔字符串未找到,返回原字符串,举例如下:
 	 *
 	 * <pre>
-	 * StrUtil.subBefore(null, *)      = null
-	 * StrUtil.subBefore("", *)        = ""
-	 * StrUtil.subBefore("abc", "a")   = ""
-	 * StrUtil.subBefore("abcba", "b") = "a"
-	 * StrUtil.subBefore("abc", "c")   = "ab"
-	 * StrUtil.subBefore("abc", "d")   = "abc"
-	 * StrUtil.subBefore("abc", "")    = ""
-	 * StrUtil.subBefore("abc", null)  = "abc"
+	 * StrUtil.subBefore(null, *, false)      = null
+	 * StrUtil.subBefore("", *, false)        = ""
+	 * StrUtil.subBefore("abc", "a", false)   = ""
+	 * StrUtil.subBefore("abcba", "b", false) = "a"
+	 * StrUtil.subBefore("abc", "c", false)   = "ab"
+	 * StrUtil.subBefore("abc", "d", false)   = "abc"
+	 * StrUtil.subBefore("abc", "", false)    = ""
+	 * StrUtil.subBefore("abc", null, false)  = "abc"
 	 * </pre>
 	 *
 	 * @param string          被查找的字符串
@@ -1783,12 +1783,12 @@ public class StrUtil {
 	 * 如果分隔字符串未找到,返回原字符串,举例如下:
 	 *
 	 * <pre>
-	 * StrUtil.subBefore(null, *)      = null
-	 * StrUtil.subBefore("", *)        = ""
-	 * StrUtil.subBefore("abc", 'a')   = ""
-	 * StrUtil.subBefore("abcba", 'b') = "a"
-	 * StrUtil.subBefore("abc", 'c')   = "ab"
-	 * StrUtil.subBefore("abc", 'd')   = "abc"
+	 * StrUtil.subBefore(null, *, false)      = null
+	 * StrUtil.subBefore("", *, false)        = ""
+	 * StrUtil.subBefore("abc", 'a', false)   = ""
+	 * StrUtil.subBefore("abcba", 'b', false) = "a"
+	 * StrUtil.subBefore("abc", 'c', false)   = "ab"
+	 * StrUtil.subBefore("abc", 'd', false)   = "abc"
 	 * </pre>
 	 *
 	 * @param string          被查找的字符串
@@ -1819,14 +1819,14 @@ public class StrUtil {
 	 * 如果分隔字符串为空串(null或""),则返回空串,如果分隔字符串未找到,返回空串,举例如下:
 	 *
 	 * <pre>
-	 * StrUtil.subAfter(null, *)      = null
-	 * StrUtil.subAfter("", *)        = ""
-	 * StrUtil.subAfter(*, null)      = ""
-	 * StrUtil.subAfter("abc", "a")   = "bc"
-	 * StrUtil.subAfter("abcba", "b") = "cba"
-	 * StrUtil.subAfter("abc", "c")   = ""
-	 * StrUtil.subAfter("abc", "d")   = ""
-	 * StrUtil.subAfter("abc", "")    = "abc"
+	 * StrUtil.subAfter(null, *, false)      = null
+	 * StrUtil.subAfter("", *, false)        = ""
+	 * StrUtil.subAfter(*, null, false)      = ""
+	 * StrUtil.subAfter("abc", "a", false)   = "bc"
+	 * StrUtil.subAfter("abcba", "b", false) = "cba"
+	 * StrUtil.subAfter("abc", "c", false)   = ""
+	 * StrUtil.subAfter("abc", "d", false)   = ""
+	 * StrUtil.subAfter("abc", "", false)    = "abc"
 	 * </pre>
 	 *
 	 * @param string          被查找的字符串
@@ -1857,12 +1857,12 @@ public class StrUtil {
 	 * 如果分隔字符串为空串(null或""),则返回空串,如果分隔字符串未找到,返回空串,举例如下:
 	 *
 	 * <pre>
-	 * StrUtil.subAfter(null, *)      = null
-	 * StrUtil.subAfter("", *)        = ""
-	 * StrUtil.subAfter("abc", 'a')   = "bc"
-	 * StrUtil.subAfter("abcba", 'b') = "cba"
-	 * StrUtil.subAfter("abc", 'c')   = ""
-	 * StrUtil.subAfter("abc", 'd')   = ""
+	 * StrUtil.subAfter(null, *, false)      = null
+	 * StrUtil.subAfter("", *, false)        = ""
+	 * StrUtil.subAfter("abc", 'a', false)   = "bc"
+	 * StrUtil.subAfter("abcba", 'b', false) = "cba"
+	 * StrUtil.subAfter("abc", 'c', false)   = ""
+	 * StrUtil.subAfter("abc", 'd', false)   = ""
 	 * </pre>
 	 *
 	 * @param string          被查找的字符串

+ 16 - 0
hutool-core/src/test/java/cn/hutool/core/bean/BeanUtilTest.java

@@ -76,6 +76,22 @@ public class BeanUtilTest {
 	}
 
 	@Test
+	public void toBeanTest(){
+		SubPerson person = new SubPerson();
+		person.setAge(14);
+		person.setOpenid("11213232");
+		person.setName("测试A11");
+		person.setSubName("sub名字");
+
+		final Map<?, ?> map = BeanUtil.toBean(person, Map.class);
+		Assert.assertEquals("测试A11", map.get("name"));
+		Assert.assertEquals(14, map.get("age"));
+		Assert.assertEquals("11213232", map.get("openid"));
+		// static属性应被忽略
+		Assert.assertFalse(map.containsKey("SUBNAME"));
+	}
+
+	@Test
 	public void mapToBeanIgnoreCaseTest() {
 		HashMap<String, Object> map = CollUtil.newHashMap();
 		map.put("Name", "Joe");

+ 11 - 5
hutool-core/src/test/java/cn/hutool/core/convert/ConvertToBeanTest.java

@@ -1,14 +1,14 @@
 package cn.hutool.core.convert;
 
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
+import cn.hutool.core.bean.BeanUtilTest.SubPerson;
 import cn.hutool.core.lang.Console;
+import cn.hutool.core.lang.TypeReference;
 import org.junit.Assert;
 import org.junit.Test;
 
-import cn.hutool.core.bean.BeanUtilTest.SubPerson;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
 
 /**
  * 类型转换工具单元测试<br>
@@ -45,6 +45,12 @@ public class ConvertToBeanTest {
 		Assert.assertEquals("测试A11", map.get("name"));
 		Assert.assertEquals("14", map.get("age"));
 		Assert.assertEquals("11213232", map.get("openid"));
+
+		final LinkedHashMap<String, String> map2 = Convert.convert(
+				new TypeReference<LinkedHashMap<String, String>>() {}, person);
+		Assert.assertEquals("测试A11", map2.get("name"));
+		Assert.assertEquals("14", map2.get("age"));
+		Assert.assertEquals("11213232", map2.get("openid"));
 	}
 
 	@Test