ソースを参照

fix LocalDateTime not support bug

Looly 6 年 前
コミット
432840be78

+ 1 - 0
CHANGELOG.md

@@ -22,6 +22,7 @@
 * 【core 】      修复scale方法透明无效问题(issue#I15L5S@Gitee)
 * 【extra】      修复exec返回无效(issue#I15L5S@Gitee)
 * 【cron】       修复CronPattern注释(pr#646@Github)
+* 【json】       修复LocalDateTime等JDK8时间对象不被支持的问题(issue#644@Github)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 54 - 33
hutool-core/src/main/java/cn/hutool/core/convert/impl/PrimitiveConverter.java

@@ -1,41 +1,46 @@
 package cn.hutool.core.convert.impl;
 
 import cn.hutool.core.convert.AbstractConverter;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.BooleanUtil;
 import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.StrUtil;
 
+import java.time.temporal.TemporalAccessor;
+import java.util.Calendar;
+import java.util.Date;
+
 /**
  * 原始类型转换器<br>
  * 支持类型为:<br>
  * <ul>
  * 		<li><code>byte</code></li>
  * 		<li><code>short</code></li>
- *		 <li><code>int</code></li>
- *		 <li><code>long</code></li>
+ * 		 <li><code>int</code></li>
+ * 		 <li><code>long</code></li>
  * 		<li><code>float</code></li>
  * 		<li><code>double</code></li>
  * 		<li><code>char</code></li>
  * 		<li><code>boolean</code></li>
  * </ul>
- * 
- * @author Looly
  *
+ * @author Looly
  */
 public class PrimitiveConverter extends AbstractConverter<Object> {
 	private static final long serialVersionUID = 1L;
-	
+
 	private Class<?> targetType;
 
 	/**
 	 * 构造<br>
+	 *
 	 * @param clazz 需要转换的原始
 	 * @throws IllegalArgumentException 传入的转换类型非原始类型时抛出
 	 */
 	public PrimitiveConverter(Class<?> clazz) {
-		if(null == clazz){
+		if (null == clazz) {
 			throw new NullPointerException("PrimitiveConverter not allow null target type!");
-		}else if(false == clazz.isPrimitive()){
+		} else if (false == clazz.isPrimitive()) {
 			throw new IllegalArgumentException("[" + clazz + "] is not a primitive class!");
 		}
 		this.targetType = clazz;
@@ -47,80 +52,95 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
 			if (byte.class == this.targetType) {
 				if (value instanceof Number) {
 					return ((Number) value).byteValue();
-				} else if(value instanceof Boolean) {
-					return BooleanUtil.toByte((Boolean)value);
+				} else if (value instanceof Boolean) {
+					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);
+				} 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 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 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);
+				} 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);
+				} 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){
-					return ((Character)value).charValue();
-				} else if(value instanceof Boolean) {
-					return BooleanUtil.toChar((Boolean)value);
+				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)) {
@@ -128,8 +148,9 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
 				}
 				return valueStr.charAt(0);
 			} else if (boolean.class == this.targetType) {
-				if(value instanceof Boolean){
-					return ((Boolean)value).booleanValue();
+				if (value instanceof Boolean) {
+					//noinspection UnnecessaryUnboxing
+					return ((Boolean) value).booleanValue();
 				}
 				String valueStr = convertToStr(value);
 				return BooleanUtil.toBoolean(valueStr);
@@ -139,12 +160,12 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
 		}
 		return 0;
 	}
-	
+
 	@Override
 	protected String convertToStr(Object value) {
 		return StrUtil.trim(super.convertToStr(value));
 	}
-	
+
 	@Override
 	@SuppressWarnings("unchecked")
 	public Class<Object> getTargetType() {

+ 17 - 8
hutool-json/src/main/java/cn/hutool/json/InternalJSONUtil.java

@@ -2,6 +2,7 @@ package cn.hutool.json;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.time.temporal.TemporalAccessor;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
@@ -43,12 +44,12 @@ final class InternalJSONUtil {
 		} else if (value instanceof JSON) {
 			((JSON) value).write(writer, indentFactor, indent);
 		} else if (value instanceof Map) {
-			new JSONObject((Map<?, ?>) value).write(writer, indentFactor, indent);
+			new JSONObject(value).write(writer, indentFactor, indent);
 		} else if (value instanceof Iterable || value instanceof Iterator || value.getClass().isArray()) {
 			new JSONArray(value).write(writer, indentFactor, indent);
 		} else if (value instanceof Number) {
 			writer.write(NumberUtil.toStr((Number) value));
-		} else if (value instanceof Date || value instanceof Calendar) {
+		} else if (value instanceof Date || value instanceof Calendar || value instanceof TemporalAccessor) {
 			final String format = (null == config) ? null : config.getDateFormat();
 			writer.write(formatDate(value, format));
 		} else if (value instanceof Boolean) {
@@ -138,7 +139,6 @@ final class InternalJSONUtil {
 	 * @return A simple JSON value.
 	 */
 	protected static Object stringToValue(String string) {
-		Double d;
 		if (null == string || "null".equalsIgnoreCase(string)) {
 			return JSONNull.NULL;
 		}
@@ -158,8 +158,8 @@ final class InternalJSONUtil {
 		if ((b >= '0' && b <= '9') || b == '-') {
 			try {
 				if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1) {
-					d = Double.valueOf(string);
-					if (!d.isInfinite() && !d.isNaN()) {
+					double d = Double.parseDouble(string);
+					if (false == Double.isInfinite(d) && false == Double.isNaN(d)) {
 						return d;
 					}
 				} else {
@@ -228,12 +228,21 @@ final class InternalJSONUtil {
 	 */
 	private static String formatDate(Object dateObj, String format) {
 		if (StrUtil.isNotBlank(format)) {
-			final Date date = (dateObj instanceof Date) ? (Date) dateObj : ((Calendar) dateObj).getTime();
 			//用户定义了日期格式
-			return JSONUtil.quote(DateUtil.format(date, format));
+			return JSONUtil.quote(DateUtil.format(Convert.toDate(dateObj), format));
 		}
 
 		//默认使用时间戳
-		return String.valueOf((dateObj instanceof Date) ? ((Date) dateObj).getTime() : ((Calendar) dateObj).getTimeInMillis());
+		long timeMillis;
+		if(dateObj instanceof TemporalAccessor){
+			timeMillis = DateUtil.toInstant((TemporalAccessor)dateObj).toEpochMilli();
+		} else if(dateObj instanceof  Date){
+			timeMillis = ((Date) dateObj).getTime();
+		} else if(dateObj instanceof Calendar){
+			timeMillis = ((Calendar) dateObj).getTimeInMillis();
+		} else{
+			throw new UnsupportedOperationException("Unsupported Date type: " + dateObj.getClass());
+		}
+		return String.valueOf(timeMillis);
 	}
 }

+ 6 - 1
hutool-json/src/main/java/cn/hutool/json/JSONUtil.java

@@ -6,6 +6,8 @@ import java.io.StringWriter;
 import java.io.Writer;
 import java.lang.reflect.Type;
 import java.nio.charset.Charset;
+import java.time.LocalDateTime;
+import java.time.temporal.TemporalAccessor;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
@@ -650,7 +652,10 @@ public final class JSONUtil {
 			}
 
 			// 日期类型原样保存,便于格式化
-			if (object instanceof Date || object instanceof Calendar) {
+			if (object instanceof Date
+					|| object instanceof Calendar
+					|| object instanceof TemporalAccessor
+			) {
 				return object;
 			}
 			// 枚举类保存其字符串形式(4.0.2新增)

+ 32 - 0
hutool-json/src/test/java/cn/hutool/json/Isse644Test.java

@@ -0,0 +1,32 @@
+package cn.hutool.json;
+
+import lombok.Data;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.time.LocalDateTime;
+
+/**
+ * 问题反馈对象中有JDK8日期对象时转换失败,5.0.7修复
+ */
+public class Isse644Test {
+
+	@Test
+	public void toBeanTest(){
+		final BeanWithDate beanWithDate = new BeanWithDate();
+		beanWithDate.setDate(LocalDateTime.now());
+
+		final JSONObject jsonObject = JSONUtil.parseObj(beanWithDate);
+
+		BeanWithDate beanWithDate2 = JSONUtil.toBean(jsonObject, BeanWithDate.class);
+		Assert.assertEquals(beanWithDate.getDate(), beanWithDate2.getDate());
+
+		beanWithDate2 = JSONUtil.toBean(jsonObject.toString(), BeanWithDate.class);
+		Assert.assertEquals(beanWithDate.getDate(), beanWithDate2.getDate());
+	}
+
+	@Data
+	static class BeanWithDate{
+		private LocalDateTime date;
+	}
+}

+ 10 - 3
hutool-json/src/test/java/cn/hutool/json/JSONObjectTest.java

@@ -3,6 +3,7 @@ package cn.hutool.json;
 import java.math.BigDecimal;
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
 
 import org.junit.Assert;
 import org.junit.Ignore;
@@ -58,8 +59,8 @@ public class JSONObjectTest {
 	 */
 	@Test
 	public void toStringTest3() {
-		JSONObject json = JSONUtil.createObj()//
-				.put("dateTime", DateUtil.parse("2019-05-02 22:12:01"))//
+		JSONObject json = Objects.requireNonNull(JSONUtil.createObj()//
+				.put("dateTime", DateUtil.parse("2019-05-02 22:12:01")))//
 				.setDateFormat(DatePattern.NORM_DATE_PATTERN);
 		Assert.assertEquals("{\"dateTime\":\"2019-05-02\"}", json.toString());
 	}
@@ -67,9 +68,10 @@ public class JSONObjectTest {
 	@Test
 	public void toStringWithDateTest() {
 		JSONObject json = JSONUtil.createObj().put("date", DateUtil.parse("2019-05-08 19:18:21"));
+		assert json != null;
 		Assert.assertEquals("{\"date\":1557314301000}", json.toString());
 		
-		json = JSONUtil.createObj().put("date", DateUtil.parse("2019-05-08 19:18:21")).setDateFormat(DatePattern.NORM_DATE_PATTERN);
+		json = Objects.requireNonNull(JSONUtil.createObj().put("date", DateUtil.parse("2019-05-08 19:18:21"))).setDateFormat(DatePattern.NORM_DATE_PATTERN);
 		Assert.assertEquals("{\"date\":\"2019-05-08\"}", json.toString());
 	}
 
@@ -131,6 +133,7 @@ public class JSONObjectTest {
 		Console.log(json2);
 	}
 
+	@SuppressWarnings("ConstantConditions")
 	@Test
 	public void toBeanTest() {
 		JSONObject subJson = JSONUtil.createObj().put("value1", "strValue1").put("value2", "234");
@@ -149,6 +152,7 @@ public class JSONObjectTest {
 		Assert.assertEquals(TestEnum.TYPE_A, bean.getTestEnum());
 	}
 
+	@SuppressWarnings("ConstantConditions")
 	@Test
 	public void toBeanNullStrTest() {
 		JSONObject json = JSONUtil.createObj()//
@@ -217,6 +221,7 @@ public class JSONObjectTest {
 	/**
 	 * 在JSON转Bean过程中,Bean中字段如果为父类定义的泛型类型,则应正确转换,此方法用于测试这类情况
 	 */
+	@SuppressWarnings("ConstantConditions")
 	@Test
 	public void toBeanTest6() {
 		JSONObject json = JSONUtil.createObj().put("targetUrl", "http://test.com").put("success", "true").put("result", JSONUtil.createObj().put("token", "tokenTest").put("userId", "测试用户1"));
@@ -271,6 +276,7 @@ public class JSONObjectTest {
 		Assert.assertEquals(bean.toString(), bean2.toString());
 	}
 
+	@SuppressWarnings("ConstantConditions")
 	@Test
 	public void parseBeanTest3() {
 		JSONObject json = JSONUtil.createObj().put("code", 22).put("data", "{\"jobId\": \"abc\", \"videoUrl\": \"http://a.com/a.mp4\"}");
@@ -310,6 +316,7 @@ public class JSONObjectTest {
 		Assert.assertEquals(DateUtil.parse("2018-10-25"), bean.getDate());
 	}
 
+	@SuppressWarnings("ConstantConditions")
 	@Test
 	public void beanTransTest3() {
 		JSONObject userAJson = JSONUtil.createObj().put("a", "AValue").put("name", "nameValue").put("date", "08:00:00");