diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a991be7a..6eb3c6e4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * 【core 】 Validator修改isCitizenId校验(pr#1032@Github) * 【core 】 增加PathUtil和FileNameUtil,分离FileUtil中部分方法 * 【core 】 改造IndexedComparator,增加InstanceComparator +* 【extra 】 增加CglibUtil ### Bug修复# * 【poi 】 修复ExcelBase.isXlsx方法判断问题(issue#I1S502@Gitee) diff --git a/hutool-extra/pom.xml b/hutool-extra/pom.xml index dc1a47ffe..b1363d249 100644 --- a/hutool-extra/pom.xml +++ b/hutool-extra/pom.xml @@ -31,6 +31,7 @@ 5.1.1 4.0.1 2.3.1.RELEASE + 3.3.0 @@ -232,6 +233,13 @@ 1.1.8 true + + cglib + cglib + ${cglib.version} + compile + true + org.springframework.boot spring-boot-starter-test diff --git a/hutool-extra/src/main/java/cn/hutool/extra/cglib/BeanCopierCache.java b/hutool-extra/src/main/java/cn/hutool/extra/cglib/BeanCopierCache.java new file mode 100644 index 000000000..7378b9090 --- /dev/null +++ b/hutool-extra/src/main/java/cn/hutool/extra/cglib/BeanCopierCache.java @@ -0,0 +1,34 @@ +package cn.hutool.extra.cglib; + +import cn.hutool.core.lang.SimpleCache; +import cn.hutool.core.lang.func.Func0; +import cn.hutool.core.util.StrUtil; +import net.sf.cglib.beans.BeanCopier; + +import java.beans.PropertyDescriptor; + +/** + * BeanCopier属性缓存
+ * 缓存用于防止多次反射造成的性能问题 + * + * @author Looly + * @since 5.4.1 + */ +public enum BeanCopierCache { + INSTANCE; + + private final SimpleCache cache = new SimpleCache<>(); + + /** + * 获得属性名和{@link PropertyDescriptor}Map映射 + * + * @param srcClass 源Bean的类 + * @param targetClass 目标Bean的类 + * @param supplier 缓存对象产生函数 + * @return 属性名和{@link PropertyDescriptor}Map映射 + * @since 5.4.1 + */ + public BeanCopier get(Class srcClass, Class targetClass, Func0 supplier) { + return this.cache.get(StrUtil.format("{}_{}", srcClass.getName(), srcClass.getName()), supplier); + } +} diff --git a/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java b/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java new file mode 100644 index 000000000..a9dedf1db --- /dev/null +++ b/hutool-extra/src/main/java/cn/hutool/extra/cglib/CglibUtil.java @@ -0,0 +1,83 @@ +package cn.hutool.extra.cglib; + +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.ReflectUtil; +import net.sf.cglib.beans.BeanCopier; +import net.sf.cglib.beans.BeanMap; +import net.sf.cglib.core.Converter; + +/** + * Cglib工具类 + * + * @author looly + * @since 5.4.1 + */ +public class CglibUtil { + + /** + * 拷贝Bean对象属性到目标类型
+ * 此方法通过指定目标类型自动创建之,然后拷贝属性 + * + * @param 目标对象类型 + * @param source 源bean对象 + * @param targetClass 目标bean类,自动实例化此对象 + */ + public static T copy(Object source, Class targetClass) { + return copy(source, targetClass, null); + } + + /** + * 拷贝Bean对象属性
+ * 此方法通过指定目标类型自动创建之,然后拷贝属性 + * + * @param 目标对象类型 + * @param source 源bean对象 + * @param targetClass 目标bean类,自动实例化此对象 + * @param converter 转换器,无需可传{@code null} + */ + public static T copy(Object source, Class targetClass, Converter converter) { + final T target = ReflectUtil.newInstanceIfPossible(targetClass); + copy(source, target); + return target; + } + + /** + * 拷贝Bean对象属性 + * + * @param source 源bean对象 + * @param target 目标bean对象 + */ + public static void copy(Object source, Object target) { + copy(source, target, null); + } + + /** + * 拷贝Bean对象属性 + * + * @param source 源bean对象 + * @param target 目标bean对象 + * @param converter 转换器,无需可传{@code null} + */ + public static void copy(Object source, Object target, Converter converter) { + Assert.notNull(source, "Source bean must be not null."); + Assert.notNull(target, "Target bean must be not null."); + + final Class sourceClass = source.getClass(); + final Class targetClass = target.getClass(); + final BeanCopier beanCopier = BeanCopierCache.INSTANCE.get( + sourceClass, targetClass, + () -> BeanCopier.create(sourceClass, targetClass, null != converter)); + + beanCopier.copy(source, target, converter); + } + + /** + * 将Bean转换为Map + * + * @param bean Bean对象 + * @return {@link BeanMap} + */ + public static BeanMap toMap(Object bean){ + return BeanMap.create(bean); + } +} diff --git a/hutool-extra/src/main/java/cn/hutool/extra/cglib/package-info.java b/hutool-extra/src/main/java/cn/hutool/extra/cglib/package-info.java new file mode 100644 index 000000000..7b5bba83d --- /dev/null +++ b/hutool-extra/src/main/java/cn/hutool/extra/cglib/package-info.java @@ -0,0 +1,7 @@ +/** + * Cglib库方法封装 + * + * @author looly + * + */ +package cn.hutool.extra.cglib; \ No newline at end of file diff --git a/hutool-extra/src/test/java/cn/hutool/extra/cglib/CglibUtilTest.java b/hutool-extra/src/test/java/cn/hutool/extra/cglib/CglibUtilTest.java new file mode 100644 index 000000000..8994bd6aa --- /dev/null +++ b/hutool-extra/src/test/java/cn/hutool/extra/cglib/CglibUtilTest.java @@ -0,0 +1,31 @@ +package cn.hutool.extra.cglib; + +import lombok.Data; +import org.junit.Assert; +import org.junit.Test; + +public class CglibUtilTest { + + @Test + public void copyTest() { + SampleBean bean = new SampleBean(); + bean.setValue("Hello world"); + + OtherSampleBean otherBean = new OtherSampleBean(); + CglibUtil.copy(bean, otherBean); + Assert.assertEquals("Hello world", otherBean.getValue()); + + OtherSampleBean otherBean2 = CglibUtil.copy(bean, OtherSampleBean.class); + Assert.assertEquals("Hello world", otherBean2.getValue()); + } + + @Data + public static class SampleBean { + private String value; + } + + @Data + public static class OtherSampleBean { + private String value; + } +}