fix LocalDateTime not support bug

This commit is contained in:
Looly 2019-12-02 18:21:10 +08:00
parent 19741683e9
commit 432840be78
6 changed files with 120 additions and 45 deletions

View File

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

View File

@ -1,18 +1,23 @@
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.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;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar;
import java.util.Date;
/** /**
* 原始类型转换器<br> * 原始类型转换器<br>
* 支持类型为<br> * 支持类型为<br>
* <ul> * <ul>
* <li><code>byte</code></li> * <li><code>byte</code></li>
* <li><code>short</code></li> * <li><code>short</code></li>
* <li><code>int</code></li> * <li><code>int</code></li>
* <li><code>long</code></li> * <li><code>long</code></li>
* <li><code>float</code></li> * <li><code>float</code></li>
* <li><code>double</code></li> * <li><code>double</code></li>
* <li><code>char</code></li> * <li><code>char</code></li>
@ -20,7 +25,6 @@ import cn.hutool.core.util.StrUtil;
* </ul> * </ul>
* *
* @author Looly * @author Looly
*
*/ */
public class PrimitiveConverter extends AbstractConverter<Object> { public class PrimitiveConverter extends AbstractConverter<Object> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -29,13 +33,14 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
/** /**
* 构造<br> * 构造<br>
*
* @param clazz 需要转换的原始 * @param clazz 需要转换的原始
* @throws IllegalArgumentException 传入的转换类型非原始类型时抛出 * @throws IllegalArgumentException 传入的转换类型非原始类型时抛出
*/ */
public PrimitiveConverter(Class<?> clazz) { public PrimitiveConverter(Class<?> clazz) {
if(null == clazz){ if (null == clazz) {
throw new NullPointerException("PrimitiveConverter not allow null target type!"); 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!"); throw new IllegalArgumentException("[" + clazz + "] is not a primitive class!");
} }
this.targetType = clazz; this.targetType = clazz;
@ -47,8 +52,8 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
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); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
@ -59,8 +64,8 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} else if (short.class == this.targetType) { } else if (short.class == this.targetType) {
if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).shortValue(); return ((Number) value).shortValue();
} else if(value instanceof Boolean) { } else if (value instanceof Boolean) {
return BooleanUtil.toShort((Boolean)value); return BooleanUtil.toShort((Boolean) value);
} }
final String valueStr = convertToStr(value); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
@ -71,9 +76,16 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} else if (int.class == this.targetType) { } else if (int.class == this.targetType) {
if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).intValue(); return ((Number) value).intValue();
} else if(value instanceof Boolean) { } else if (value instanceof Boolean) {
return BooleanUtil.toInt((Boolean)value); 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); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
return 0; return 0;
@ -83,9 +95,16 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} else if (long.class == this.targetType) { } else if (long.class == this.targetType) {
if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).longValue(); return ((Number) value).longValue();
} else if(value instanceof Boolean) { } else if (value instanceof Boolean) {
return BooleanUtil.toLong((Boolean)value); 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); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
return 0; return 0;
@ -95,8 +114,8 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} else if (float.class == this.targetType) { } else if (float.class == this.targetType) {
if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).floatValue(); return ((Number) value).floatValue();
} else if(value instanceof Boolean) { } else if (value instanceof Boolean) {
return BooleanUtil.toFloat((Boolean)value); return BooleanUtil.toFloat((Boolean) value);
} }
final String valueStr = convertToStr(value); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
@ -107,8 +126,8 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} else if (double.class == this.targetType) { } else if (double.class == this.targetType) {
if (value instanceof Number) { if (value instanceof Number) {
return ((Number) value).doubleValue(); return ((Number) value).doubleValue();
} else if(value instanceof Boolean) { } else if (value instanceof Boolean) {
return BooleanUtil.toDouble((Boolean)value); return BooleanUtil.toDouble((Boolean) value);
} }
final String valueStr = convertToStr(value); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
@ -117,10 +136,11 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
return Double.parseDouble(valueStr); return Double.parseDouble(valueStr);
} else if (char.class == this.targetType) { } else if (char.class == this.targetType) {
if(value instanceof Character){ if (value instanceof Character) {
return ((Character)value).charValue(); //noinspection UnnecessaryUnboxing
} else if(value instanceof Boolean) { return ((Character) value).charValue();
return BooleanUtil.toChar((Boolean)value); } else if (value instanceof Boolean) {
return BooleanUtil.toChar((Boolean) value);
} }
final String valueStr = convertToStr(value); final String valueStr = convertToStr(value);
if (StrUtil.isBlank(valueStr)) { if (StrUtil.isBlank(valueStr)) {
@ -128,8 +148,9 @@ public class PrimitiveConverter extends AbstractConverter<Object> {
} }
return valueStr.charAt(0); return valueStr.charAt(0);
} else if (boolean.class == this.targetType) { } else if (boolean.class == this.targetType) {
if(value instanceof Boolean){ if (value instanceof Boolean) {
return ((Boolean)value).booleanValue(); //noinspection UnnecessaryUnboxing
return ((Boolean) value).booleanValue();
} }
String valueStr = convertToStr(value); String valueStr = convertToStr(value);
return BooleanUtil.toBoolean(valueStr); return BooleanUtil.toBoolean(valueStr);

View File

@ -2,6 +2,7 @@ package cn.hutool.json;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@ -43,12 +44,12 @@ final class InternalJSONUtil {
} else if (value instanceof JSON) { } else if (value instanceof JSON) {
((JSON) value).write(writer, indentFactor, indent); ((JSON) value).write(writer, indentFactor, indent);
} else if (value instanceof Map) { } 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()) { } else if (value instanceof Iterable || value instanceof Iterator || value.getClass().isArray()) {
new JSONArray(value).write(writer, indentFactor, indent); new JSONArray(value).write(writer, indentFactor, indent);
} else if (value instanceof Number) { } else if (value instanceof Number) {
writer.write(NumberUtil.toStr((Number) value)); 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(); final String format = (null == config) ? null : config.getDateFormat();
writer.write(formatDate(value, format)); writer.write(formatDate(value, format));
} else if (value instanceof Boolean) { } else if (value instanceof Boolean) {
@ -138,7 +139,6 @@ final class InternalJSONUtil {
* @return A simple JSON value. * @return A simple JSON value.
*/ */
protected static Object stringToValue(String string) { protected static Object stringToValue(String string) {
Double d;
if (null == string || "null".equalsIgnoreCase(string)) { if (null == string || "null".equalsIgnoreCase(string)) {
return JSONNull.NULL; return JSONNull.NULL;
} }
@ -158,8 +158,8 @@ final class InternalJSONUtil {
if ((b >= '0' && b <= '9') || b == '-') { if ((b >= '0' && b <= '9') || b == '-') {
try { try {
if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1) { if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1) {
d = Double.valueOf(string); double d = Double.parseDouble(string);
if (!d.isInfinite() && !d.isNaN()) { if (false == Double.isInfinite(d) && false == Double.isNaN(d)) {
return d; return d;
} }
} else { } else {
@ -228,12 +228,21 @@ final class InternalJSONUtil {
*/ */
private static String formatDate(Object dateObj, String format) { private static String formatDate(Object dateObj, String format) {
if (StrUtil.isNotBlank(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);
} }
} }

View File

@ -6,6 +6,8 @@ import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.Date; 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; return object;
} }
// 枚举类保存其字符串形式4.0.2新增 // 枚举类保存其字符串形式4.0.2新增

View File

@ -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;
}
}

View File

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