From 6d8d51ceca68564d1f9bb81a2ad87c964777cf9a Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 4 May 2023 13:54:30 +0800 Subject: [PATCH] fix code --- hutool-core/pom.xml | 16 ---- .../copier/provider/BeanValueProvider.java | 56 +++++++++++++ .../copier/provider/MapValueProvider.java | 49 +++++++++++ .../core/convert/CompositeConverter.java | 6 ++ .../core/convert/impl/BeanConverter.java | 1 + .../core/convert/impl/KBeanConverter.java | 82 +++++++++++++++++++ .../hutool/core/reflect/MethodHandleUtil.java | 5 ++ .../hutool/core/reflect/kotlin/KCallable.java | 14 ++++ .../core/reflect/kotlin/KClassUtil.java | 70 +++++++++++++++- .../hutool/core/convert/ConvertKBeanTest.java | 36 ++++++++ .../hutool/core/net/url/IssueI6ZF6KTest.java | 33 ++++++++ .../core/reflect/kotlin/KClassUtilTest.java | 29 +++++++ hutool-http/pom.xml | 4 +- .../hutool/json/convert/JSONConverter.java | 7 ++ .../json/convert/JSONGetterValueProvider.java | 48 +++++++++++ .../hutool/json/issueI5WDP0/ERPProduct.kt | 18 ++++ .../json/issueI5WDP0/JsonToBeanTest.java | 28 +++++++ pom.xml | 14 ++++ 18 files changed, 496 insertions(+), 20 deletions(-) create mode 100755 hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/BeanValueProvider.java create mode 100755 hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/MapValueProvider.java create mode 100755 hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/KBeanConverter.java create mode 100755 hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertKBeanTest.java create mode 100755 hutool-core/src/test/java/org/dromara/hutool/core/net/url/IssueI6ZF6KTest.java create mode 100755 hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java create mode 100755 hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/ERPProduct.kt create mode 100755 hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java diff --git a/hutool-core/pom.xml b/hutool-core/pom.xml index 4926e742b..4b93fd533 100755 --- a/hutool-core/pom.xml +++ b/hutool-core/pom.xml @@ -30,22 +30,6 @@ org.dromara.hutool.core - 1.8.21 - - - org.jetbrains.kotlin - kotlin-stdlib - ${kotlin-version} - test - - - org.jetbrains.kotlin - kotlin-reflect - ${kotlin-version} - test - - - diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/BeanValueProvider.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/BeanValueProvider.java new file mode 100755 index 000000000..134fc1e0e --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/BeanValueProvider.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.bean.copier.provider; + +import org.dromara.hutool.core.bean.BeanDesc; +import org.dromara.hutool.core.bean.BeanUtil; +import org.dromara.hutool.core.bean.PropDesc; +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.core.convert.Convert; + +import java.lang.reflect.Type; + +/** + * Bean值提供器 + * + * @author looly + */ +public class BeanValueProvider implements ValueProvider { + + private final Object bean; + private final BeanDesc beanDesc; + + /** + * 构造 + * + * @param bean Bean + */ + public BeanValueProvider(final Object bean) { + this.bean = bean; + this.beanDesc = BeanUtil.getBeanDesc(bean.getClass()); + } + + @Override + public Object value(final String key, final Type valueType) { + final PropDesc prop = beanDesc.getProp(key); + if (null != prop) { + return Convert.convert(valueType, prop.getValue(bean)); + } + return null; + } + + @Override + public boolean containsKey(final String key) { + return null != beanDesc.getProp(key); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/MapValueProvider.java b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/MapValueProvider.java new file mode 100755 index 000000000..9e116da62 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/bean/copier/provider/MapValueProvider.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.bean.copier.provider; + +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.core.convert.Convert; + +import java.lang.reflect.Type; +import java.util.Map; + +/** + * Map值提供者 + * + * @author looly + */ +@SuppressWarnings("rawtypes") +public class MapValueProvider implements ValueProvider { + + private final Map map; + + /** + * 构造 + * + * @param map map + */ + public MapValueProvider(final Map map) { + this.map = map; + } + + @Override + public Object value(final String key, final Type valueType) { + return Convert.convert(valueType, map.get(key)); + } + + @Override + public boolean containsKey(final String key) { + return map.containsKey(key); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java index c49b77eee..d7b8845a0 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/CompositeConverter.java @@ -16,6 +16,7 @@ import org.dromara.hutool.core.bean.BeanUtil; import org.dromara.hutool.core.convert.impl.*; import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.util.ObjUtil; import java.lang.reflect.Type; @@ -145,6 +146,11 @@ public class CompositeConverter extends RegisterConverter { return result; } + // Kotlin Bean + if(KClassUtil.isKotlinClass(rowType)){ + return (T) KBeanConverter.INSTANCE.convert(type, value); + } + // 尝试转Bean if (BeanUtil.isBean(rowType)) { return (T) BeanConverter.INSTANCE.convert(type, value); diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java index caa3a5b2f..65112f1a8 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/BeanConverter.java @@ -23,6 +23,7 @@ import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.map.MapProxy; import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import java.io.Serializable; import java.lang.reflect.Type; diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/KBeanConverter.java b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/KBeanConverter.java new file mode 100755 index 000000000..1ca2c1c99 --- /dev/null +++ b/hutool-core/src/main/java/org/dromara/hutool/core/convert/impl/KBeanConverter.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.convert.impl; + +import org.dromara.hutool.core.bean.BeanUtil; +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.core.bean.copier.provider.BeanValueProvider; +import org.dromara.hutool.core.bean.copier.provider.MapValueProvider; +import org.dromara.hutool.core.convert.ConvertException; +import org.dromara.hutool.core.convert.Converter; +import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.reflect.kotlin.KClassUtil; + +import java.io.Serializable; +import java.lang.reflect.Type; +import java.util.Map; + +/** + * Kotlin Bean转换器,支持: + *
+ * Map =》 Bean
+ * Bean =》 Bean
+ * ValueProvider =》 Bean
+ * 
+ * + * @author Looly + */ +public class KBeanConverter implements Converter, Serializable { + private static final long serialVersionUID = 1L; + + /** + * 单例对象 + */ + public static KBeanConverter INSTANCE = new KBeanConverter(); + + @Override + public Object convert(final Type targetType, final Object value) throws ConvertException { + Assert.notNull(targetType); + if (null == value) { + return null; + } + + // value本身实现了Converter接口,直接调用 + if(value instanceof Converter){ + return ((Converter) value).convert(targetType, value); + } + + final Class targetClass = TypeUtil.getClass(targetType); + Assert.notNull(targetClass, "Target type is not a class!"); + + return convertInternal(targetType, targetClass, value); + } + + @SuppressWarnings("unchecked") + private Object convertInternal(final Type targetType, final Class targetClass, final Object value) { + ValueProvider valueProvider = null; + if(value instanceof ValueProvider){ + valueProvider = (ValueProvider) value; + } else if(value instanceof Map){ + valueProvider = new MapValueProvider((Map) value); + } else if(BeanUtil.isBean(value.getClass())){ + valueProvider = new BeanValueProvider(value); + } + + if(null != valueProvider){ + return KClassUtil.newInstance(targetClass, valueProvider); + } + + throw new ConvertException("Unsupported source type: [{}] to [{}]", value.getClass(), targetType); + } +} diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java index 12d650d8f..80092b12d 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/MethodHandleUtil.java @@ -16,6 +16,7 @@ import org.dromara.hutool.core.bean.NullWrapperBean; import org.dromara.hutool.core.convert.Convert; import org.dromara.hutool.core.exception.HutoolException; import org.dromara.hutool.core.lang.Assert; +import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.reflect.lookup.LookupUtil; import java.lang.invoke.MethodHandle; @@ -139,6 +140,10 @@ public class MethodHandleUtil { */ private static Object[] actualArgs(final Method method, final Object[] args) { final Class[] parameterTypes = method.getParameterTypes(); + if(1 == parameterTypes.length && parameterTypes[0].isArray()){ + // 可变长参数,不做转换 + return args; + } final Object[] actualArgs = new Object[parameterTypes.length]; if (null != args) { for (int i = 0; i < actualArgs.length; i++) { diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KCallable.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KCallable.java index 2896e500b..9c0fd9fee 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KCallable.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KCallable.java @@ -25,11 +25,14 @@ import java.util.List; * @author VampireAchao, Looly */ public class KCallable { + private static final Method METHOD_GET_PARAMETERS; + private static final Method METHOD_CALL; static { final Class kFunctionClass = ClassLoaderUtil.loadClass("kotlin.reflect.KCallable"); METHOD_GET_PARAMETERS = MethodUtil.getMethod(kFunctionClass, "getParameters"); + METHOD_CALL = MethodUtil.getMethodByName(kFunctionClass, "call"); } /** @@ -46,4 +49,15 @@ public class KCallable { } return result; } + + /** + * 实例化对象,本质上调用KCallable.call方法 + * + * @param kCallable kotlin的类、方法或构造 + * @param args 参数列表 + * @return 参数列表 + */ + public static Object call(final Object kCallable, final Object... args) { + return MethodUtil.invoke(kCallable, METHOD_CALL, new Object[]{args}); + } } diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KClassUtil.java b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KClassUtil.java index d1ca297c4..83f370e70 100644 --- a/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KClassUtil.java +++ b/hutool-core/src/main/java/org/dromara/hutool/core/reflect/kotlin/KClassUtil.java @@ -12,9 +12,13 @@ package org.dromara.hutool.core.reflect.kotlin; +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.core.bean.copier.provider.MapValueProvider; import org.dromara.hutool.core.lang.Opt; +import java.lang.annotation.Annotation; import java.util.List; +import java.util.Map; /** * Kotlin反射包装相关工具类 @@ -23,11 +27,25 @@ import java.util.List; */ public class KClassUtil { + @SuppressWarnings("unchecked") + private static final Class META_DATA_CLASS = + (Class) Opt.ofTry(() -> Class.forName("kotlin.Metadata")).get(); + /** * 是否提供或处于Kotlin环境中 */ - public static final boolean IS_KOTLIN_ENABLE = - Opt.ofTry(() -> Class.forName("kotlin.Metadata")).isPresent(); + public static final boolean IS_KOTLIN_ENABLE = null != META_DATA_CLASS; + + /** + * 检查给定的类是否为Kotlin类
+ * Kotlin类带有@kotlin.Metadata注解 + * + * @param clazz 类 + * @return 是否Kotlin类 + */ + public static boolean isKotlinClass(final Class clazz) { + return IS_KOTLIN_ENABLE && clazz.isAnnotationPresent(META_DATA_CLASS); + } /** * 获取Kotlin类的所有构造方法 @@ -48,4 +66,52 @@ public class KClassUtil { public static List getParameters(final Object kCallable) { return KCallable.getParameters(kCallable); } + + /** + * 从{@link ValueProvider}中提取对应name的参数列表 + * + * @param kCallable kotlin的类、方法或构造 + * @param valueProvider {@link ValueProvider} + * @return 参数数组 + */ + public static Object[] getParameterValues(final Object kCallable, final ValueProvider valueProvider) { + final List parameters = getParameters(kCallable); + final Object[] args = new Object[parameters.size()]; + KParameter kParameter; + for (int i = 0; i < parameters.size(); i++) { + kParameter = parameters.get(i); + args[i] = valueProvider.value(kParameter.getName(), kParameter.getType()); + } + return args; + } + + /** + * 实例化Kotlin对象 + * + * @param 对象类型 + * @param targetType 对象类型 + * @param map 参数名和参数值的Map + * @return 对象 + */ + public static T newInstance(final Class targetType, final Map map) { + return newInstance(targetType, new MapValueProvider(map)); + } + + /** + * 实例化Kotlin对象 + * + * @param 对象类型 + * @param targetType 对象类型 + * @param valueProvider 值提供器,用于提供构造所需参数值 + * @return 对象 + */ + @SuppressWarnings("unchecked") + public static T newInstance(final Class targetType, final ValueProvider valueProvider) { + final List constructors = getConstructors(targetType); + for (final Object constructor : constructors) { + final Object[] parameterValues = getParameterValues(constructor, valueProvider); + return (T) KCallable.call(constructor, parameterValues); + } + return null; + } } diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertKBeanTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertKBeanTest.java new file mode 100755 index 000000000..e53bf5130 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/convert/ConvertKBeanTest.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.convert; + +import org.dromara.hutool.core.reflect.kotlin.TestKBean; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; + +public class ConvertKBeanTest { + + @Test + void mapToBeanTest(){ + final HashMap map = new HashMap<>(); + map.put("country", "中国"); + map.put("age", 18); + map.put("id", "VampireAchao"); + + final TestKBean testKBean = Convert.convert(TestKBean.class, map); + + Assertions.assertEquals("VampireAchao", testKBean.getId()); + Assertions.assertEquals("中国", testKBean.getCountry()); + Assertions.assertNull(testKBean.getName()); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/net/url/IssueI6ZF6KTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/net/url/IssueI6ZF6KTest.java new file mode 100755 index 000000000..9b03950c8 --- /dev/null +++ b/hutool-core/src/test/java/org/dromara/hutool/core/net/url/IssueI6ZF6KTest.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.core.net.url; + +import org.dromara.hutool.core.lang.Console; +import org.dromara.hutool.core.map.MapBuilder; +import org.dromara.hutool.core.util.CharsetUtil; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +public class IssueI6ZF6KTest { + + @Test + void buildQueryTest() { + final String json = "{\"keyword\":\"国际 英语 c&b\",\"anyKeyword\":\"1\"}"; + final Map form = MapBuilder.of() + .put("condition", json) + .build(); + final String requestBody = URLUtil.buildQuery(form, CharsetUtil.UTF_8); + Console.log(requestBody); + } +} diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/reflect/kotlin/KClassUtilTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/reflect/kotlin/KClassUtilTest.java index 74b9aa87f..28810cf50 100644 --- a/hutool-core/src/test/java/org/dromara/hutool/core/reflect/kotlin/KClassUtilTest.java +++ b/hutool-core/src/test/java/org/dromara/hutool/core/reflect/kotlin/KClassUtilTest.java @@ -12,13 +12,28 @@ package org.dromara.hutool.core.reflect.kotlin; +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.core.bean.copier.provider.MapValueProvider; +import org.dromara.hutool.core.convert.Convert; +import org.dromara.hutool.core.map.MapUtil; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.lang.reflect.Type; +import java.util.HashMap; import java.util.List; public class KClassUtilTest { + @Test + void isKotlinClassTest() { + boolean kotlinClass = KClassUtil.isKotlinClass(TestKBean.class); + Assertions.assertTrue(kotlinClass); + + kotlinClass = KClassUtil.isKotlinClass(KClassUtilTest.class); + Assertions.assertFalse(kotlinClass); + } + @Test void getConstructorTest() { final List constructors = KClassUtil.getConstructors(TestKBean.class); @@ -39,4 +54,18 @@ public class KClassUtilTest { Assertions.assertEquals("name", parameters.get(1).getName()); Assertions.assertEquals("country", parameters.get(2).getName()); } + + @Test + void newInstanceTest() { + final HashMap argsMap = new HashMap<>(); + argsMap.put("country", "中国"); + argsMap.put("age", 18); + argsMap.put("id", "VampireAchao"); + + final TestKBean testKBean = KClassUtil.newInstance(TestKBean.class, argsMap); + + Assertions.assertEquals("VampireAchao", testKBean.getId()); + Assertions.assertEquals("中国", testKBean.getCountry()); + Assertions.assertNull(testKBean.getName()); + } } diff --git a/hutool-http/pom.xml b/hutool-http/pom.xml index 14238d91b..d043e11a2 100755 --- a/hutool-http/pom.xml +++ b/hutool-http/pom.xml @@ -85,6 +85,7 @@ provided + org.dromara.hutool hutool-json @@ -97,7 +98,6 @@ 0.1.2 test - org.slf4j slf4j-simple @@ -107,7 +107,7 @@ com.squareup.okhttp3 mockwebserver - 4.10.0 + 4.11.0 test diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java index 83f387e15..40e99b865 100644 --- a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONConverter.java @@ -20,10 +20,12 @@ import org.dromara.hutool.core.convert.ConvertException; import org.dromara.hutool.core.convert.Converter; import org.dromara.hutool.core.convert.RegisterConverter; import org.dromara.hutool.core.convert.impl.*; +import org.dromara.hutool.core.lang.Console; import org.dromara.hutool.core.map.MapWrapper; import org.dromara.hutool.core.reflect.ConstructorUtil; import org.dromara.hutool.core.reflect.TypeReference; import org.dromara.hutool.core.reflect.TypeUtil; +import org.dromara.hutool.core.reflect.kotlin.KClassUtil; import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.util.ObjUtil; import org.dromara.hutool.json.*; @@ -210,6 +212,11 @@ public class JSONConverter implements Converter { // 尝试转Bean if (BeanUtil.isBean(rawType)) { + // issue#I5WDP0 对于Kotlin对象,由于参数可能非空限制,导致无法创建一个默认的对象再赋值 + if(KClassUtil.isKotlinClass(rawType) && json instanceof JSONGetter){ + return KClassUtil.newInstance(rawType, new JSONGetterValueProvider<>((JSONGetter)json)); + } + return BeanCopier.of(json, ConstructorUtil.newInstanceIfPossible(rawType), targetType, InternalJSONUtil.toCopyOptions(json.config())).copy(); diff --git a/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java new file mode 100755 index 000000000..946116e77 --- /dev/null +++ b/hutool-json/src/main/java/org/dromara/hutool/json/convert/JSONGetterValueProvider.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.json.convert; + +import org.dromara.hutool.core.bean.copier.ValueProvider; +import org.dromara.hutool.json.JSONGetter; + +import java.lang.reflect.Type; + +/** + * JSONGetter的ValueProvider + * + * @param 键类型 + * @author looly + */ +public class JSONGetterValueProvider implements ValueProvider { + + private final JSONGetter jsonGetter; + + /** + * 构造 + * + * @param jsonGetter {@link JSONGetter} + */ + public JSONGetterValueProvider(final JSONGetter jsonGetter) { + this.jsonGetter = jsonGetter; + } + + @Override + public Object value(final K key, final Type valueType) { + return jsonGetter.get(key, valueType); + } + + @Override + public boolean containsKey(final K key) { + return !jsonGetter.isNull(key); + } +} diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/ERPProduct.kt b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/ERPProduct.kt new file mode 100755 index 000000000..42c20c354 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/ERPProduct.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.json.issueI5WDP0 + +data class ERPProduct( + var code:String, + var status:String +) diff --git a/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java new file mode 100755 index 000000000..d3525a2a0 --- /dev/null +++ b/hutool-json/src/test/java/org/dromara/hutool/json/issueI5WDP0/JsonToBeanTest.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 looly(loolly@aliyun.com) + * Hutool is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +package org.dromara.hutool.json.issueI5WDP0; + +import org.dromara.hutool.json.JSONUtil; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class JsonToBeanTest { + @Test + void toBeanTest() { + final String jsonStr = "{\"code\": \"201\", \"status\": \"ok\"}"; + final ERPProduct bean = JSONUtil.toBean(jsonStr, ERPProduct.class); + Assertions.assertNotNull(bean); + Assertions.assertEquals("201", bean.getCode()); + Assertions.assertEquals("ok", bean.getStatus()); + } +} diff --git a/pom.xml b/pom.xml index d3d9e40e4..0cf97a708 100755 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ 8 5.9.2 1.18.26 + 1.8.21 @@ -67,6 +68,19 @@ ${lombok.version} test + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin-version} + test + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin-version} + test +