fix methoda

This commit is contained in:
Looly 2020-08-02 19:26:24 +08:00
parent c47272922b
commit d07feb9065
9 changed files with 239 additions and 134 deletions

View File

@ -9,8 +9,11 @@
* 【socket】 对NioServer和NioClient改造pr#992@Github * 【socket】 对NioServer和NioClient改造pr#992@Github
* 【core 】 StrUtil增加filter方法pr#149@Gitee * 【core 】 StrUtil增加filter方法pr#149@Gitee
* 【core 】 DateUtil增加beginOfWeek重载 * 【core 】 DateUtil增加beginOfWeek重载
* 【core 】 将有歧义的BeanUtil.mapToBean方法置为过期使用toBean方法
### Bug修复# ### Bug修复#
* 【core 】 修复原始类型转换时,转换失败没有抛出异常的问题
* 【core 】 修复BeanUtil.mapToBean中bean的class非空构造无法实例化问题
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------

View File

@ -52,7 +52,7 @@ public class BeanUtil {
* *
* @param clazz 待测试类 * @param clazz 待测试类
* @return 是否为可读的Bean对象 * @return 是否为可读的Bean对象
* @see #hasGetter(Class) * @see #hasGetter(Class)
* @see #hasPublicField(Class) * @see #hasPublicField(Class)
*/ */
public static boolean isReadableBean(Class<?> clazz) { public static boolean isReadableBean(Class<?> clazz) {
@ -342,9 +342,11 @@ public class BeanUtil {
* @param beanClass Bean Class * @param beanClass Bean Class
* @param isIgnoreError 是否忽略注入错误 * @param isIgnoreError 是否忽略注入错误
* @return Bean * @return Bean
* @deprecated 请使用 {@link #toBean(Object, Class)} {@link #toBeanIgnoreError(Object, Class)}
*/ */
@Deprecated
public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass, boolean isIgnoreError) { public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass, boolean isIgnoreError) {
return fillBeanWithMap(map, ReflectUtil.newInstance(beanClass), isIgnoreError); return fillBeanWithMap(map, ReflectUtil.newInstanceIfPossible(beanClass), isIgnoreError);
} }
/** /**
@ -356,9 +358,11 @@ public class BeanUtil {
* @param beanClass Bean Class * @param beanClass Bean Class
* @param isIgnoreError 是否忽略注入错误 * @param isIgnoreError 是否忽略注入错误
* @return Bean * @return Bean
* @deprecated 请使用 {@link #toBeanIgnoreCase(Object, Class, boolean)}
*/ */
@Deprecated
public static <T> T mapToBeanIgnoreCase(Map<?, ?> map, Class<T> beanClass, boolean isIgnoreError) { public static <T> T mapToBeanIgnoreCase(Map<?, ?> map, Class<T> beanClass, boolean isIgnoreError) {
return fillBeanWithMapIgnoreCase(map, ReflectUtil.newInstance(beanClass), isIgnoreError); return fillBeanWithMapIgnoreCase(map, ReflectUtil.newInstanceIfPossible(beanClass), isIgnoreError);
} }
/** /**
@ -369,9 +373,25 @@ public class BeanUtil {
* @param beanClass Bean Class * @param beanClass Bean Class
* @param copyOptions 转Bean选项 * @param copyOptions 转Bean选项
* @return Bean * @return Bean
* @deprecated 请使用 {@link #toBean(Object, Class, CopyOptions)}
*/ */
@Deprecated
public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass, CopyOptions copyOptions) { public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass, CopyOptions copyOptions) {
return fillBeanWithMap(map, ReflectUtil.newInstance(beanClass), copyOptions); return fillBeanWithMap(map, ReflectUtil.newInstanceIfPossible(beanClass), copyOptions);
}
/**
* Map转换为Bean对象
*
* @param <T> Bean类型
* @param map {@link Map}
* @param beanClass Bean Class
* @param isToCamelCase 是否将Map中的下划线风格key转换为驼峰风格
* @param copyOptions 转Bean选项
* @return Bean
*/
public static <T> T mapToBean(Map<?, ?> map, Class<T> beanClass, boolean isToCamelCase, CopyOptions copyOptions) {
return fillBeanWithMap(map, ReflectUtil.newInstanceIfPossible(beanClass), isToCamelCase, copyOptions);
} }
// --------------------------------------------------------------------------------------------- fillBeanWithMap // --------------------------------------------------------------------------------------------- fillBeanWithMap
@ -447,7 +467,8 @@ public class BeanUtil {
if (isToCamelCase) { if (isToCamelCase) {
map = MapUtil.toCamelCaseMap(map); map = MapUtil.toCamelCaseMap(map);
} }
return BeanCopier.create(map, bean, copyOptions).copy(); copyProperties(map, bean, copyOptions);
return bean;
} }
// --------------------------------------------------------------------------------------------- fillBean // --------------------------------------------------------------------------------------------- fillBean
@ -465,6 +486,36 @@ public class BeanUtil {
return toBean(source, clazz, null); return toBean(source, clazz, null);
} }
/**
* 对象或Map转Bean忽略字段转换时发生的异常
*
* @param <T> 转换的Bean类型
* @param source Bean对象或Map
* @param clazz 目标的Bean类型
* @return Bean对象
* @since 5.4.0
*/
public static <T> T toBeanIgnoreError(Object source, Class<T> clazz) {
return toBean(source, clazz, CopyOptions.create().setIgnoreError(true));
}
/**
* 对象或Map转Bean忽略字段转换时发生的异常
*
* @param <T> 转换的Bean类型
* @param source Bean对象或Map
* @param clazz 目标的Bean类型
* @param ignoreError 是否忽略注入错误
* @return Bean对象
* @since 5.4.0
*/
public static <T> T toBeanIgnoreCase(Object source, Class<T> clazz, boolean ignoreError) {
return toBean(source, clazz,
CopyOptions.create()
.setIgnoreCase(true)
.setIgnoreError(ignoreError));
}
/** /**
* 对象或Map转Bean * 对象或Map转Bean
* *
@ -491,7 +542,7 @@ public class BeanUtil {
* @return Bean * @return Bean
*/ */
public static <T> T toBean(Class<T> beanClass, ValueProvider<String> valueProvider, CopyOptions copyOptions) { public static <T> T toBean(Class<T> beanClass, ValueProvider<String> valueProvider, CopyOptions copyOptions) {
return fillBean(ReflectUtil.newInstance(beanClass), valueProvider, copyOptions); return fillBean(ReflectUtil.newInstanceIfPossible(beanClass), valueProvider, copyOptions);
} }
/** /**
@ -608,9 +659,9 @@ public class BeanUtil {
/** /**
* 按照Bean对象属性创建对应的Class对象并忽略某些属性 * 按照Bean对象属性创建对应的Class对象并忽略某些属性
* *
* @param <T> 对象类型 * @param <T> 对象类型
* @param source 源Bean对象 * @param source 源Bean对象
* @param tClass 目标Class * @param tClass 目标Class
* @param ignoreProperties 不拷贝的的属性列表 * @param ignoreProperties 不拷贝的的属性列表
* @return 目标对象 * @return 目标对象
*/ */
@ -690,7 +741,7 @@ public class BeanUtil {
final Field[] fields = ReflectUtil.getFields(bean.getClass()); final Field[] fields = ReflectUtil.getFields(bean.getClass());
for (Field field : fields) { for (Field field : fields) {
if(ModifierUtil.isStatic(field)){ if (ModifierUtil.isStatic(field)) {
continue; continue;
} }
if (ignoreFields != null && ArrayUtil.containsIgnoreCase(ignoreFields, field.getName())) { if (ignoreFields != null && ArrayUtil.containsIgnoreCase(ignoreFields, field.getName())) {
@ -737,7 +788,7 @@ public class BeanUtil {
public static boolean isEmpty(Object bean, String... ignoreFiledNames) { public static boolean isEmpty(Object bean, String... ignoreFiledNames) {
if (null != bean) { if (null != bean) {
for (Field field : ReflectUtil.getFields(bean.getClass())) { for (Field field : ReflectUtil.getFields(bean.getClass())) {
if(ModifierUtil.isStatic(field)){ if (ModifierUtil.isStatic(field)) {
continue; continue;
} }
if ((false == ArrayUtil.contains(ignoreFiledNames, field.getName())) if ((false == ArrayUtil.contains(ignoreFiledNames, field.getName()))
@ -763,7 +814,7 @@ public class BeanUtil {
return true; return true;
} }
for (Field field : ReflectUtil.getFields(bean.getClass())) { for (Field field : ReflectUtil.getFields(bean.getClass())) {
if(ModifierUtil.isStatic(field)){ if (ModifierUtil.isStatic(field)) {
continue; continue;
} }
if ((false == ArrayUtil.contains(ignoreFiledNames, field.getName()))// if ((false == ArrayUtil.contains(ignoreFiledNames, field.getName()))//

View File

@ -609,9 +609,8 @@ public class Convert {
* @since 4.0.7 * @since 4.0.7
* @throws ConvertException 转换器不存在 * @throws ConvertException 转换器不存在
*/ */
@SuppressWarnings("unchecked")
public static <T> T convertByClassName(String className, Object value) throws ConvertException{ public static <T> T convertByClassName(String className, Object value) throws ConvertException{
return (T) convert(ClassUtil.loadClass(className), value); return convert(ClassUtil.loadClass(className), value);
} }
/** /**

View File

@ -5,6 +5,7 @@ import cn.hutool.core.bean.copier.BeanCopier;
import cn.hutool.core.bean.copier.CopyOptions; 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.convert.AbstractConverter; import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.map.MapProxy; import cn.hutool.core.map.MapProxy;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.ReflectUtil;
@ -79,7 +80,8 @@ public class BeanConverter<T> extends AbstractConverter<T> {
// 尝试反序列化 // 尝试反序列化
return ObjectUtil.deserialize((byte[])value); return ObjectUtil.deserialize((byte[])value);
} }
return null;
throw new ConvertException("Unsupported source type: {}", value.getClass());
} }
@Override @Override

View File

@ -1,6 +1,7 @@
package cn.hutool.core.convert.impl; package cn.hutool.core.convert.impl;
import cn.hutool.core.convert.AbstractConverter; import cn.hutool.core.convert.AbstractConverter;
import cn.hutool.core.convert.ConvertException;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.NumberUtil;
@ -48,117 +49,114 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
@Override @Override
protected Object convertInternal(Object value) { protected Object convertInternal(Object value) {
try { if (byte.class == this.targetType) {
if (byte.class == this.targetType) { if (value instanceof Number) {
if (value instanceof Number) { return ((Number) value).byteValue();
return ((Number) value).byteValue(); } else if (value instanceof Boolean) {
} else if (value instanceof Boolean) { return BooleanUtil.toByte((Boolean) value);
return BooleanUtil.toByte((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Byte.parseByte(valueStr);
} else if (short.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).shortValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toShort((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Short.parseShort(valueStr);
} else if (int.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toInt((Boolean) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Calendar) {
return ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return NumberUtil.parseInt(valueStr);
} else if (long.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toLong((Boolean) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Calendar) {
return ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return NumberUtil.parseLong(valueStr);
} else if (float.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).floatValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toFloat((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Float.parseFloat(valueStr);
} else if (double.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).doubleValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toDouble((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Double.parseDouble(valueStr);
} else if (char.class == this.targetType) {
if (value instanceof Character) {
//noinspection UnnecessaryUnboxing
return ((Character) value).charValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toChar((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return valueStr.charAt(0);
} else if (boolean.class == this.targetType) {
if (value instanceof Boolean) {
//noinspection UnnecessaryUnboxing
return ((Boolean) value).booleanValue();
}
String valueStr = convertToStr(value);
return BooleanUtil.toBoolean(valueStr);
} }
} catch (Exception e) { final String valueStr = convertToStr(value);
// Ignore Exception if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Byte.parseByte(valueStr);
} else if (short.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).shortValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toShort((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Short.parseShort(valueStr);
} else if (int.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).intValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toInt((Boolean) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Calendar) {
return ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return NumberUtil.parseInt(valueStr);
} else if (long.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).longValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toLong((Boolean) value);
} else if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Calendar) {
return ((Calendar) value).getTimeInMillis();
} else if (value instanceof TemporalAccessor) {
return DateUtil.toInstant((TemporalAccessor) value).toEpochMilli();
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return NumberUtil.parseLong(valueStr);
} else if (float.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).floatValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toFloat((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Float.parseFloat(valueStr);
} else if (double.class == this.targetType) {
if (value instanceof Number) {
return ((Number) value).doubleValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toDouble((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return Double.parseDouble(valueStr);
} else if (char.class == this.targetType) {
if (value instanceof Character) {
//noinspection UnnecessaryUnboxing
return ((Character) value).charValue();
} else if (value instanceof Boolean) {
return BooleanUtil.toChar((Boolean) value);
}
final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) {
return 0;
}
return valueStr.charAt(0);
} else if (boolean.class == this.targetType) {
if (value instanceof Boolean) {
//noinspection UnnecessaryUnboxing
return ((Boolean) value).booleanValue();
}
final String valueStr = convertToStr(value);
return BooleanUtil.toBoolean(valueStr);
} }
return 0;
throw new ConvertException("Unsupported target type: {}", this.targetType);
} }
@Override @Override

View File

@ -178,7 +178,7 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
* @return vo * @return vo
*/ */
public <T> T toBean(Class<T> clazz) { public <T> T toBean(Class<T> clazz) {
return BeanUtil.mapToBean(this, clazz, false); return BeanUtil.toBean(this, clazz);
} }
/** /**
@ -189,7 +189,7 @@ public class Dict extends LinkedHashMap<String, Object> implements BasicTypeGett
* @return vo * @return vo
*/ */
public <T> T toBeanIgnoreCase(Class<T> clazz) { public <T> T toBeanIgnoreCase(Class<T> clazz) {
return BeanUtil.mapToBeanIgnoreCase(this, clazz, false); return BeanUtil.toBeanIgnoreCase(this, clazz, false);
} }
/** /**

View File

@ -1,12 +1,12 @@
package cn.hutool.core.text.replacer; package cn.hutool.core.text.replacer;
import cn.hutool.core.text.StrBuilder;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import cn.hutool.core.text.StrBuilder;
/** /**
* 查找替换器通过查找指定关键字替换对应的值 * 查找替换器通过查找指定关键字替换对应的值
* *
@ -27,8 +27,8 @@ public class LookupReplacer extends StrReplacer {
* @param lookup 被查找的键值对 * @param lookup 被查找的键值对
*/ */
public LookupReplacer(String[]... lookup) { public LookupReplacer(String[]... lookup) {
this.lookupMap = new HashMap<String, String>(); this.lookupMap = new HashMap<>();
this.prefixSet = new HashSet<Character>(); this.prefixSet = new HashSet<>();
int minLength = Integer.MAX_VALUE; int minLength = Integer.MAX_VALUE;
int maxLength = 0; int maxLength = 0;

View File

@ -92,13 +92,29 @@ public class BeanUtilTest {
Assert.assertFalse(map.containsKey("SUBNAME")); Assert.assertFalse(map.containsKey("SUBNAME"));
} }
/**
* 忽略转换错误测试
*/
@Test
public void toBeanIgnoreErrorTest(){
HashMap<String, Object> map = CollUtil.newHashMap();
map.put("name", "Joe");
// 错误的类型此处忽略
map.put("age", "aaaaaa");
Person person = BeanUtil.toBeanIgnoreError(map, Person.class);
Assert.assertEquals("Joe", person.getName());
// 错误的类型不copy这个字段使用对象创建的默认值
Assert.assertEquals(0, person.getAge());
}
@Test @Test
public void mapToBeanIgnoreCaseTest() { public void mapToBeanIgnoreCaseTest() {
HashMap<String, Object> map = CollUtil.newHashMap(); HashMap<String, Object> map = CollUtil.newHashMap();
map.put("Name", "Joe"); map.put("Name", "Joe");
map.put("aGe", 12); map.put("aGe", 12);
Person person = BeanUtil.mapToBeanIgnoreCase(map, Person.class, false); Person person = BeanUtil.toBeanIgnoreCase(map, Person.class, false);
Assert.assertEquals("Joe", person.getName()); Assert.assertEquals("Joe", person.getName());
Assert.assertEquals(12, person.getAge()); Assert.assertEquals(12, person.getAge());
} }
@ -114,7 +130,7 @@ public class BeanUtilTest {
mapping.put("a_name", "name"); mapping.put("a_name", "name");
mapping.put("b_age", "age"); mapping.put("b_age", "age");
Person person = BeanUtil.mapToBean(map, Person.class, CopyOptions.create().setFieldMapping(mapping)); Person person = BeanUtil.toBean(map, Person.class, CopyOptions.create().setFieldMapping(mapping));
Assert.assertEquals("Joe", person.getName()); Assert.assertEquals("Joe", person.getName());
Assert.assertEquals(12, person.getAge()); Assert.assertEquals(12, person.getAge());
} }
@ -128,11 +144,22 @@ public class BeanUtilTest {
map.put("name", "Joe"); map.put("name", "Joe");
map.put("age", 12); map.put("age", 12);
Person2 person = BeanUtil.mapToBean(map, Person2.class, CopyOptions.create()); // 非空构造也可以实例化成功
Person2 person = BeanUtil.toBean(map, Person2.class, CopyOptions.create());
Assert.assertEquals("Joe", person.name); Assert.assertEquals("Joe", person.name);
Assert.assertEquals(12, person.age); Assert.assertEquals(12, person.age);
} }
/**
* 测试在不忽略错误情况下转换失败需要报错
*/
@Test(expected = NumberFormatException.class)
public void mapToBeanWinErrorTest() {
Map<String, String> map = new HashMap<>();
map.put("age", "哈哈");
Person user = BeanUtil.toBean(map, Person.class);
}
@Test @Test
public void beanToMapTest() { public void beanToMapTest() {
SubPerson person = new SubPerson(); SubPerson person = new SubPerson();
@ -181,7 +208,7 @@ public class BeanUtilTest {
map.put("aliasSubName", "sub名字"); map.put("aliasSubName", "sub名字");
map.put("slow", true); map.put("slow", true);
final SubPersonWithAlias subPersonWithAlias = BeanUtil.mapToBean(map, SubPersonWithAlias.class, false); final SubPersonWithAlias subPersonWithAlias = BeanUtil.toBean(map, SubPersonWithAlias.class);
Assert.assertEquals("sub名字", subPersonWithAlias.getSubName()); Assert.assertEquals("sub名字", subPersonWithAlias.getSubName());
} }
@ -345,6 +372,13 @@ public class BeanUtilTest {
} }
public static class Person2 { public static class Person2 {
public Person2(String name, int age, String openid) {
this.name = name;
this.age = age;
this.openid = openid;
}
public String name; public String name;
public int age; public int age;
public String openid; public String openid;

View File

@ -0,0 +1,18 @@
package cn.hutool.core.convert;
import org.junit.Assert;
import org.junit.Test;
public class PrimitiveConvertTest {
@Test
public void toIntTest(){
final int convert = Convert.convert(int.class, "123");
Assert.assertEquals(123, convert);
}
@Test(expected = NumberFormatException.class)
public void toIntErrorTest(){
final int convert = Convert.convert(int.class, "aaaa");
}
}