mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-07-21 15:09:48 +08:00
fix code
This commit is contained in:
@@ -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<String> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -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<String> {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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转换器,支持:
|
||||
* <pre>
|
||||
* Map =》 Bean
|
||||
* Bean =》 Bean
|
||||
* ValueProvider =》 Bean
|
||||
* </pre>
|
||||
*
|
||||
* @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<String> valueProvider = null;
|
||||
if(value instanceof ValueProvider){
|
||||
valueProvider = (ValueProvider<String>) value;
|
||||
} else if(value instanceof Map){
|
||||
valueProvider = new MapValueProvider((Map<String, ?>) 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);
|
||||
}
|
||||
}
|
@@ -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++) {
|
||||
|
@@ -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});
|
||||
}
|
||||
}
|
||||
|
@@ -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<? extends Annotation> META_DATA_CLASS =
|
||||
(Class<? extends Annotation>) 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类<br>
|
||||
* 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<KParameter> 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<String> valueProvider) {
|
||||
final List<KParameter> 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 <T> 对象类型
|
||||
* @param targetType 对象类型
|
||||
* @param map 参数名和参数值的Map
|
||||
* @return 对象
|
||||
*/
|
||||
public static <T> T newInstance(final Class<T> targetType, final Map<String, ?> map) {
|
||||
return newInstance(targetType, new MapValueProvider(map));
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化Kotlin对象
|
||||
*
|
||||
* @param <T> 对象类型
|
||||
* @param targetType 对象类型
|
||||
* @param valueProvider 值提供器,用于提供构造所需参数值
|
||||
* @return 对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T newInstance(final Class<T> targetType, final ValueProvider<String> 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;
|
||||
}
|
||||
}
|
||||
|
@@ -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<String, Object> 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());
|
||||
}
|
||||
}
|
@@ -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<String, Object> form = MapBuilder.<String, Object>of()
|
||||
.put("condition", json)
|
||||
.build();
|
||||
final String requestBody = URLUtil.buildQuery(form, CharsetUtil.UTF_8);
|
||||
Console.log(requestBody);
|
||||
}
|
||||
}
|
@@ -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<String, Object> 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());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user