浏览代码

fic null point bug

Looly 5 年之前
父节点
当前提交
9f40666c95

+ 2 - 1
CHANGELOG.md

@@ -13,7 +13,8 @@
 ### Bug修复
 ### Bug修复
 * 【db     】     修复PageResult.isLast计算问题
 * 【db     】     修复PageResult.isLast计算问题
 * 【cron   】     修复更改系统时间后CronTimer被阻塞的问题(issue#838@Github)
 * 【cron   】     修复更改系统时间后CronTimer被阻塞的问题(issue#838@Github)
-* 【db     】     修复Page.addOrder无效问题(issue#838@Github)
+* 【db     】     修复Page.addOrder无效问题(issue#I1F9MZ@Gitee)
+* 【json   】     修复JSONConvert转换日期空指针问题(issue#I1F8M2@Gitee)
 
 
 -------------------------------------------------------------------------------------------------------------
 -------------------------------------------------------------------------------------------------------------
 ## 5.3.1 (2020-04-17)
 ## 5.3.1 (2020-04-17)

+ 4 - 1
hutool-core/src/main/java/cn/hutool/core/bean/copier/BeanCopier.java

@@ -130,7 +130,10 @@ public class BeanCopier<T> implements Copier<T>, Serializable {
 	 * @param bean Bean
 	 * @param bean Bean
 	 */
 	 */
 	private void mapToBean(Map<?, ?> map, Object bean) {
 	private void mapToBean(Map<?, ?> map, Object bean) {
-		valueProviderToBean(new MapValueProvider(map, this.copyOptions.ignoreCase), bean);
+		valueProviderToBean(
+				new MapValueProvider(map, this.copyOptions.ignoreCase, this.copyOptions.ignoreError),
+				bean
+		);
 	}
 	}
 
 
 	/**
 	/**

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

@@ -18,7 +18,7 @@ public interface ValueProvider<T>{
 	 * 返回值一般需要匹配被注入类型,如果不匹配会调用默认转换 Convert#convert(Type, Object)实现转换
 	 * 返回值一般需要匹配被注入类型,如果不匹配会调用默认转换 Convert#convert(Type, Object)实现转换
 	 * 
 	 * 
 	 * @param key Bean对象中参数名
 	 * @param key Bean对象中参数名
-	 * @param valueType 被注入的值类型
+	 * @param valueType 被注入的值类型
 	 * @return 对应参数名的值
 	 * @return 对应参数名的值
 	 */
 	 */
 	Object value(T key, Type valueType);
 	Object value(T key, Type valueType);

+ 7 - 3
hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/BeanValueProvider.java

@@ -3,6 +3,7 @@ package cn.hutool.core.bean.copier.provider;
 import cn.hutool.core.bean.BeanDesc.PropDesc;
 import cn.hutool.core.bean.BeanDesc.PropDesc;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.bean.copier.ValueProvider;
 import cn.hutool.core.bean.copier.ValueProvider;
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.exceptions.UtilException;
 import cn.hutool.core.exceptions.UtilException;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 
 
@@ -42,20 +43,23 @@ public class BeanValueProvider implements ValueProvider<String> {
 			//boolean类型字段字段名支持两种方式
 			//boolean类型字段字段名支持两种方式
 			sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
 			sourcePd = sourcePdMap.get(StrUtil.upperFirstAndAddPre(key, "is"));
 		}
 		}
-		
+
+		Object result = null;
 		if (null != sourcePd) {
 		if (null != sourcePd) {
 			final Method getter = sourcePd.getGetter();
 			final Method getter = sourcePd.getGetter();
 			if (null != getter) {
 			if (null != getter) {
 				try {
 				try {
-					return getter.invoke(source);
+					result = getter.invoke(source);
 				} catch (Exception e) {
 				} catch (Exception e) {
 					if (false == ignoreError) {
 					if (false == ignoreError) {
 						throw new UtilException(e, "Inject [{}] error!", key);
 						throw new UtilException(e, "Inject [{}] error!", key);
 					}
 					}
 				}
 				}
+
+				result = Convert.convertWithCheck(valueType,result, null, ignoreError);
 			}
 			}
 		}
 		}
-		return null;
+		return result;
 	}
 	}
 
 
 	@Override
 	@Override

+ 15 - 2
hutool-core/src/main/java/cn/hutool/core/bean/copier/provider/MapValueProvider.java

@@ -17,14 +17,26 @@ import java.util.Map;
 public class MapValueProvider implements ValueProvider<String> {
 public class MapValueProvider implements ValueProvider<String> {
 
 
 	private final Map<?, ?> map;
 	private final Map<?, ?> map;
+	private final boolean ignoreError;
 
 
 	/**
 	/**
 	 * 构造
 	 * 构造
-	 * 
+	 *
 	 * @param map Map
 	 * @param map Map
 	 * @param ignoreCase 是否忽略key的大小写
 	 * @param ignoreCase 是否忽略key的大小写
 	 */
 	 */
 	public MapValueProvider(Map<?, ?> map, boolean ignoreCase) {
 	public MapValueProvider(Map<?, ?> map, boolean ignoreCase) {
+		this(map, ignoreCase, false);
+	}
+
+	/**
+	 * 构造
+	 * 
+	 * @param map Map
+	 * @param ignoreCase 是否忽略key的大小写
+	 * @since 5.3.2
+	 */
+	public MapValueProvider(Map<?, ?> map, boolean ignoreCase, boolean ignoreError) {
 		if(false == ignoreCase || map instanceof CaseInsensitiveMap) {
 		if(false == ignoreCase || map instanceof CaseInsensitiveMap) {
 			//不忽略大小写或者提供的Map本身为CaseInsensitiveMap则无需转换
 			//不忽略大小写或者提供的Map本身为CaseInsensitiveMap则无需转换
 			this.map = map;
 			this.map = map;
@@ -32,6 +44,7 @@ public class MapValueProvider implements ValueProvider<String> {
 			//转换为大小写不敏感的Map
 			//转换为大小写不敏感的Map
 			this.map = new CaseInsensitiveMap<>(map);
 			this.map = new CaseInsensitiveMap<>(map);
 		}
 		}
+		this.ignoreError = ignoreError;
 	}
 	}
 
 
 	@Override
 	@Override
@@ -42,7 +55,7 @@ public class MapValueProvider implements ValueProvider<String> {
 			value = map.get(StrUtil.toUnderlineCase(key));
 			value = map.get(StrUtil.toUnderlineCase(key));
 		}
 		}
 
 
-		return Convert.convert(valueType, value);
+		return Convert.convertWithCheck(valueType, value, null, this.ignoreError);
 	}
 	}
 
 
 	@Override
 	@Override

+ 38 - 12
hutool-core/src/main/java/cn/hutool/core/convert/Convert.java

@@ -1,14 +1,5 @@
 package cn.hutool.core.convert;
 package cn.hutool.core.convert;
 
 
-import java.lang.reflect.Type;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.nio.charset.Charset;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
 import cn.hutool.core.convert.impl.CollectionConverter;
 import cn.hutool.core.convert.impl.CollectionConverter;
 import cn.hutool.core.convert.impl.EnumConverter;
 import cn.hutool.core.convert.impl.EnumConverter;
 import cn.hutool.core.convert.impl.MapConverter;
 import cn.hutool.core.convert.impl.MapConverter;
@@ -20,6 +11,21 @@ import cn.hutool.core.util.ClassUtil;
 import cn.hutool.core.util.HexUtil;
 import cn.hutool.core.util.HexUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
 
 
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.charset.Charset;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
 /**
 /**
  * 类型转换器
  * 类型转换器
  * 
  * 
@@ -674,7 +680,7 @@ public class Convert {
 	 * @throws ConvertException 转换器不存在
 	 * @throws ConvertException 转换器不存在
 	 */
 	 */
 	public static <T> T convert(Type type, Object value, T defaultValue) throws ConvertException {
 	public static <T> T convert(Type type, Object value, T defaultValue) throws ConvertException {
-		return ConverterRegistry.getInstance().convert(type, value, defaultValue);
+		return convertWithCheck(type, value, defaultValue, false);
 	}
 	}
 	
 	
 	/**
 	/**
@@ -703,10 +709,30 @@ public class Convert {
 	 * @since 4.5.10
 	 * @since 4.5.10
 	 */
 	 */
 	public static <T> T convertQuietly(Type type, Object value, T defaultValue) {
 	public static <T> T convertQuietly(Type type, Object value, T defaultValue) {
+		return convertWithCheck(type, value, defaultValue, true);
+	}
+
+	/**
+	 * 转换值为指定类型,可选是否不抛异常转换<br>
+	 * 当转换失败时返回默认值
+	 *
+	 * @param <T> 目标类型
+	 * @param type 目标类型
+	 * @param value 值
+	 * @param defaultValue 默认值
+	 * @param quietly 是否静默转换,true不抛异常
+	 * @return 转换后的值
+	 * @since 5.3.2
+	 */
+	public static <T> T convertWithCheck(Type type, Object value, T defaultValue, boolean quietly) {
+		final ConverterRegistry registry = ConverterRegistry.getInstance();
 		try {
 		try {
-			return convert(type, value, defaultValue);
+			return registry.convert(type, value, defaultValue);
 		} catch (Exception e) {
 		} catch (Exception e) {
-			return defaultValue;
+			if(quietly){
+				return defaultValue;
+			}
+			throw e;
 		}
 		}
 	}
 	}
 	
 	

+ 5 - 0
hutool-core/src/main/java/cn/hutool/core/convert/impl/TemporalAccessorConverter.java

@@ -4,6 +4,7 @@ import cn.hutool.core.convert.AbstractConverter;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 
 
 import java.time.Instant;
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDate;
@@ -107,6 +108,10 @@ public class TemporalAccessorConverter extends AbstractConverter<TemporalAccesso
 	 * @return 日期对象
 	 * @return 日期对象
 	 */
 	 */
 	private TemporalAccessor parseFromCharSequence(CharSequence value) {
 	private TemporalAccessor parseFromCharSequence(CharSequence value) {
+		if(StrUtil.isBlank(value)){
+			return null;
+		}
+
 		final Instant instant;
 		final Instant instant;
 		ZoneId zoneId;
 		ZoneId zoneId;
 		if (null != this.format) {
 		if (null != this.format) {

+ 6 - 12
hutool-json/src/main/java/cn/hutool/json/JSONConverter.java

@@ -71,22 +71,16 @@ public class JSONConverter implements Converter<JSON> {
 		}
 		}
 		
 		
 		if(value instanceof JSON) {
 		if(value instanceof JSON) {
-			JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType);
+			final JSONDeserializer<?> deserializer = GlobalSerializeMapping.getDeserializer(targetType);
 			if(null != deserializer) {
 			if(null != deserializer) {
 				return (T) deserializer.deserialize((JSON)value);
 				return (T) deserializer.deserialize((JSON)value);
 			}
 			}
 		}
 		}
 
 
-		Object targetValue;
-		try {
-			targetValue = Convert.convert(targetType, value);
-		} catch (ConvertException e) {
-			if (ignoreError) {
-				return null;
-			}
-			throw e;
-		}
-		
+		final T targetValue = ignoreError ?
+				Convert.convertQuietly(targetType, value):
+				Convert.convert(targetType, value);
+
 		if (null == targetValue && false == ignoreError) {
 		if (null == targetValue && false == ignoreError) {
 			if (StrUtil.isBlankIfStr(value)) {
 			if (StrUtil.isBlankIfStr(value)) {
 				// 对于传入空字符串的情况,如果转换的目标对象是非字符串或非原始类型,转换器会返回false。
 				// 对于传入空字符串的情况,如果转换的目标对象是非字符串或非原始类型,转换器会返回false。
@@ -97,7 +91,7 @@ public class JSONConverter implements Converter<JSON> {
 			throw new ConvertException("Can not convert {} to type {}", value, ObjectUtil.defaultIfNull(TypeUtil.getClass(targetType), targetType));
 			throw new ConvertException("Can not convert {} to type {}", value, ObjectUtil.defaultIfNull(TypeUtil.getClass(targetType), targetType));
 		}
 		}
 
 
-		return (T) targetValue;
+		return targetValue;
 	}
 	}
 
 
 	@Override
 	@Override

+ 38 - 0
hutool-json/src/test/java/cn/hutool/json/IssueI1F8M2.java

@@ -0,0 +1,38 @@
+package cn.hutool.json;
+
+import lombok.Data;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.time.LocalDateTime;
+
+/**
+ * https://gitee.com/loolly/dashboard/issues?id=I1F8M2
+ */
+public class IssueI1F8M2 {
+	@Test
+	public void toBeanTest() {
+		String jsonStr = "{\"eventType\":\"fee\",\"fwdAlertingTime\":\"2020-04-22 16:34:13\",\"fwdAnswerTime\":\"\"}";
+		Param param = JSONUtil.toBean(jsonStr, Param.class);
+		Assert.assertEquals("2020-04-22T16:34:13", param.getFwdAlertingTime().toString());
+		Assert.assertNull(param.getFwdAnswerTime());
+	}
+
+	// Param类的字段
+	@Data
+	static class Param {
+		/**
+		 * fee表示话单事件
+		 */
+		private String eventType;
+		/**
+		 * 转接呼叫后振铃时间
+		 */
+		private LocalDateTime fwdAlertingTime;
+		/**
+		 * 转接呼叫后应答时间
+		 */
+		private LocalDateTime fwdAnswerTime;
+
+	}
+}