Skip to content

Commit

Permalink
Merge pull request #5 from tanyaofei/0.1.5
Browse files Browse the repository at this point in the history
0.1.5
  • Loading branch information
tanyaofei authored Jan 12, 2023
2 parents 0f7262f + be6674f commit 3dfcf6e
Show file tree
Hide file tree
Showing 34 changed files with 1,173 additions and 668 deletions.
39 changes: 22 additions & 17 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
# 更新日志

+ 0.1.5
+ 新增 `new BeanCopierImpl(builder -> builder.preferNested)` 等更多配置
+ **修复生成转换器时生成类名可能出现死循环的问题**
+ 更多预检测

+ 0.1.4
+ 支持通过 `new BeanCopier(new MyClassLoader())` 创建指定类加载器的 `BeanCopierImpl`
+ `BeanCopier` 的类加载器由原来的 `ConverterClassLoader` 替换为 `AppClassLoader`
+ 修复列表递归拷贝元素包含 `null` 时会抛出异常的问题
+ 优化拷贝效率并减少内存占用
+ `asm` 依赖库升级到 `9.4`
+ 支持通过 `new BeanCopierImpl(new MyClassLoader())` 创建指定类加载器的 `BeanCopierImpl`
+ `BeanCopier` 的类加载器由原来的 `ConverterClassLoader` 修改为自动选取
+ 修复集合嵌套拷贝元素包含 `null` 时会抛出异常的问题
+ 优化拷贝效率并减少内存占用
+ `asm` 依赖库升级到 `9.4``

+ 0.1.3
+ 大幅度优化批量拷贝的速度 `BeanCopier.cloneList()``BeanCopier.copyList()`, 拷贝一百万个对象由 `200ms+`
缩减到 `20ms+`
+ 修复 `BeanCopier.cloneList` 第一个元素为 null 时会出现 `NullPointerException` 的 bug
+ 大幅度优化批量拷贝的速度 `BeanCopier.cloneList()``BeanCopier.copyList()`, 拷贝一百万个对象由 `200ms+`
缩减到 `20ms+`
+ 修复 `BeanCopier.cloneList` 第一个元素为 null 时会出现 `NullPointerException` 的 bug

+ 0.1.2
+ 除了提供 `BeanCopier` 的静态方法以外,现在可 `new BeanCopierImpl()` 来创建拷贝对象,适用于有类卸载需求的场景
+ 更多测试用例
+ 除了提供 `BeanCopier` 的静态方法以外,现在可 `new BeanCopierImpl()` 来创建拷贝对象,适用于有类卸载需求的场景
+ 更多测试用例

+ 0.1.1
+ 修正一些 bug
+ 完全的泛型兼容, `List<Integer>` 现在可以拷贝到 `List<? extends Number>`, `IntegerBox extends Box<Integer>`
现在可以拷贝到 `Box<Integer>`
+ 修正一些 bug
+ 完全的泛型兼容, `List<Integer>` 现在可以拷贝到 `List<? extends Number>`, `IntegerBox extends Box<Integer>`
现在可以拷贝到 `Box<Integer>`

+ 0.1.0
+ 新增 `@Property` 注解支持字段别名和跳过字段选项
+ 新增 `@Property` 注解支持字段别名和跳过字段选项

+ 0.0.8
+ lombok 依赖 `scope` 修改为 `provided`
+ lombok 依赖 `scope` 修改为 `provided`

+ 0.0.7
+ 不拷贝提供了参数数量不正确的 `getter``setter`
+ 不拷贝提供了参数数量不正确的 `getter``setter`

+ 0.0.5
+ 基础类型 `boolean``getter` 方法修改为 `isXxxx()`
+ 基础类型 `boolean``getter` 方法修改为 `isXxxx()`
65 changes: 53 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

1. [X] 相同名称相同类型拷贝: `String` -> `String`
2. [X] 完全兼容的泛型拷贝: `StringValue` -> `Value<String>`
3. [X] 递归拷贝
3. [X] 嵌套拷贝,集合嵌套拷贝: `Source` -> `Source`, `List<Source>` -> `Collection<Target>`
4. [X] 向上转型拷贝: `Integer` -> `Number`, `ArrayList<Integer>` -> `List<Number>`
5. [X] 拷贝父类字段
6. [X] 字段别名: `@Property(value = "aliasName")`
Expand All @@ -21,7 +21,7 @@
<!-- https://mvnrepository.com/artifact/io.github.tanyaofei/beancopier -->
<groupId>io.github.tanyaofei</groupId>
<artifactId>beancopier</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
</dependency>
```

Expand Down Expand Up @@ -76,7 +76,7 @@ public class Main {
}
```

## 递归拷贝
## 嵌套拷贝

```java
import io.github.tanyaofei.beancopier.BeanCopier;
Expand Down Expand Up @@ -243,6 +243,42 @@ public class Target {
}
```

# 可选配置项

通过以下方法可以创建一个自定义配置的 `BeanCopierImpl` 实例

```java
import io.github.tanyaofei.beancopier.BeanCopierImpl;
import io.github.tanyaofei.beancopier.NamingPolicy;

public class Test {
public static void main(String[] args) {
BeanCopierImpl beanCopier = new BeanCopierImpl(builder ->
builder
.preferNested(true)
.includingSuper(true)
.skipNull(false)
.propertySupported(true)
.classLoader(ClassLoader.getSystemClassLoader())
.namingPolicy(NamingPolicy.getDefault())
.fullTypeMatching(false)
.classDumpPath("./target")
);
}
}
```

以下是可选的配置项

| 配置项 | 默认值 | 作用 |
|---------------------|---------|----------------------------------------------|
| `preferNested` | `true` | 是否进行嵌套拷贝,如果嵌套拷贝包含循环引用,请勿使用 |
| `skipNull` | `false` | 是否跳过来源字段为 `null` 的字段,`false` 意味着目标字段的默认值不会生效 |
| `propertySupported` | `true` | 是否启用对 `@Property` 注解的支持 |
| `classloader` | `null` | 指定使用特定的类加载器对生成出来的转换器类进行加载 |
| `fullTypeMatching` | `false` | 是否严格完整匹配类型,为 `ture` 表示关闭向上转型、泛型兼容等字段的拷贝 |
| `classDumpPath` | `null` | 生成的转换器 class 文件导出位置 |

# 选择 ClassLoader

在 Java 中,不同的类加载器加载出来的类无法相互访问,但是具继承关系的类加载器可以访问父加载器加载的类。在 `beancopier`
Expand All @@ -261,7 +297,7 @@ graph
1. `MyClassLoader1` 无法访问 `DefaultClassLoader``MyClassLoader2`
2. `DefaultClassLoader` 无法访问 `MyClassLoader1``MyClassLoader2`
3. `MyClassLoader2` 可以访问 `MyClassLoader1`
4. 所有 `MyClassLoader` 都可以访问 `AppClassLoader``ExtClassLoader``BootstrapClassLoader`
4. `MyClassLoader``MyClassLoader2`, `DefaultClassLoader` 都可以访问 `AppClassLoader``ExtClassLoader``BootstrapClassLoader`

`beancopier` 具有三种情况使用不同的 `ClassLoader`

Expand Down Expand Up @@ -298,12 +334,17 @@ public class Main {

# 版本记录

+ 0.1.5
+ 新增 `new BeanCopierImpl(builder -> builder.preferNested)` 等更多配置
+ **修复生成转换器时生成类名可能出现死循环的问题**
+ 更多预检测

+ 0.1.4
+ 支持通过 `new BeanCopier(new MyClassLoader())` 创建指定类加载器的 `BeanCopierImpl`
+ `BeanCopier` 的类加载器由原来的 `ConverterClassLoader` 替换为 `AppClassLoader`
+ 修复列表递归拷贝元素包含 `null` 时会抛出异常的问题
+ 优化拷贝效率并减少内存占用
+ `asm` 依赖库升级到 `9.4`
+ 支持通过 `new BeanCopierImpl(new MyClassLoader())` 创建指定类加载器的 `BeanCopierImpl`
+ `BeanCopier` 的类加载器由原来的 `ConverterClassLoader` 修改为自动选取
+ 修复集合嵌套拷贝元素包含 `null` 时会抛出异常的问题
+ 优化拷贝效率并减少内存占用
+ `asm` 依赖库升级到 `9.4`

+ 0.1.3
+ 大幅度优化批量拷贝的速度 `BeanCopier.cloneList()``BeanCopier.copyList()`, 拷贝一百万个对象由 `200ms+`
Expand Down Expand Up @@ -367,9 +408,9 @@ public class StandardSourToStandardDestConverter$$GeneratedByBeanCopier$$ba69502
```java
import java.util.List;

public class RecursionSourToRecursionDestConverter$$GeneratedByBeanCopier$$41d66bc9 implements Converter<NormalTest.RecursionSour, NormalTest.RecursionDest> {
public NormalTest.RecursionDest convert(NormalTest.RecursionSour var1) {
NormalTest.RecursionDest var2 = new NormalTest.RecursionDest();
public class NestedSourToNestedDestConverter$$GeneratedByBeanCopier$$41d66bc9 implements Converter<NormalTest.NestedSour, NormalTest.NestedDest> {
public NormalTest.NestedDest convert(NormalTest.NestedSour var1) {
NormalTest.NestedDest var2 = new NormalTest.NestedDest();
if (var1.getA() != null) {
var2.setA(this.convert(var1.getA()));
}
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>io.github.tanyaofei</groupId>
<artifactId>beancopier</artifactId>
<version>0.1.4</version>
<version>0.1.5</version>
<name>beancopier</name>

<url>https://github.com/tanyaofei/beancopier</url>
Expand Down Expand Up @@ -71,7 +71,7 @@
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<groupId>io.github.tanyaofei</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
Expand Down
99 changes: 76 additions & 23 deletions src/main/java/io/github/tanyaofei/beancopier/BeanCopier.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
/**
* 对象拷贝器
* <p>
* 为了方便简单使用, 此类维护着一个{@link BeanCopierImpl} 的默认实例 {@link BeanCopierImpl#getInstance()}. 可以使用这个类定义的静态方法进行对象拷贝, 也可以通过 {@code new BeanCopierImpl()} 自行创建.
* 如果在项目中使用有类卸载需求, 则应该自行创建 {@link BeanCopierImpl}, 那么类卸载的流程应当如下:
* 为了方便简单使用,此类维护着一个{@link BeanCopierImpl} 的默认实例 {@link BeanCopierImpl#getInstance()}。 可以使用这个类定义的静态方法进行对象拷贝, 这些静态方法都是对 {@link BeanCopierImpl} 的调用。
* 也可以通过 {@code new BeanCopierImpl()} 自行创建对象拷贝器,如果在项目中使用有类卸载需求, 则应该自行创建 {@link BeanCopierImpl},
* 那么类卸载的流程应当如下:
* </p>
* <ol>
* <li>{@link BeanCopierImpl} 实例不再引用并被 GC 掉</li>
Expand All @@ -22,62 +23,114 @@
* 这个 BeanCopier 生成的转换器将会由 app classloader 进行加载, 因此基本上不可能进行类卸载
* </p>
* <p><i>注意: 类的卸载依赖垃圾回收器具有类卸载能力</i></p>
*
* @since 0.0.1
* @author tanyaofei
* @see BeanCopierImpl
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class BeanCopier {

private final static BeanCopierImpl IMPL = BeanCopierImpl.getInstance();
private final static BeanCopierImpl theCopier = BeanCopierImpl.getInstance();


/**
* {@link BeanCopierImpl#copy(Object, Class)}
* 拷贝对象, 实例化一个 target 并将 source 的字段拷贝到 target
*
* @param source 拷贝来源
* @param target 拷贝目标类
* @param <S> 拷贝来源类型
* @param <T> 拷贝目标类型
* @return 拷贝目标
* @see BeanCopierImpl#copy(Object, Class)
*/
public static <S, T> T copy(S source, Class<T> targetClass) {
return IMPL.copy(source, targetClass, null);
public static <S, T> T copy(S source, Class<T> target) {
return theCopier.copy(source, target, null);
}


/**
* {@link BeanCopierImpl#copy(Object, Class, Callback)}
* 拷贝对象, 在拷贝完之后将会调用 callback 进行回调操作
* <pre>{@code
* Source source = new Source();
* source.setVal("val);
* Target target = BeanCopier.copy(s, Target.class, (s, t) -> t.setVal2("val2"));
* }</pre>
*
* @param source 拷贝来源
* @param target 拷贝目标类
* @param callback 回调动作
* @param <S> 拷贝来源类
* @param <T> 拷贝目标类
* @return 拷贝目标
* @see BeanCopierImpl#copy(Object, Class, Callback)
*/
public static <S, T> T copy(S source, Class<T> targetClass, Callback<S, T> callback) {
return IMPL.copy(source, targetClass, callback);
public static <S, T> T copy(S source, Class<T> target, Callback<S, T> callback) {
return theCopier.copy(source, target, callback);
}

/**
* {@link BeanCopierImpl#clone(Object)}
* 克隆对象
*
* @param source 克隆对象
* @param <T> 克隆对象类
* @return 克隆出来的对象
* @see BeanCopierImpl#clone(Object)
*/
public static <T> T clone(T source) {
return IMPL.clone(source);
return theCopier.clone(source);
}

/**
* {@link BeanCopierImpl#cloneList(Collection)}
* 批量克隆对象
*
* @param sources 克隆对象集合,不能为 null。如果元素为 null 则拷贝出来的元素也为 null
* @param <T> 克隆对象类
* @return 被克隆出来的对象集合
*/
public static <T> List<T> cloneList(Collection<T> sources) {
return IMPL.cloneList(sources, null);
return theCopier.cloneList(sources, null);
}

/**
* {@link BeanCopierImpl#cloneList(Collection, Callback)}
* 批量克隆对象
*
* @param sources 克隆对象集合, 不能为 null。如果元素为 null 则拷贝出来的元素也为 null
* @param callback 每克隆一次对象都会调用一次 callback,要注意如果元素为 null 则 callback 中的参数也为 null
* @param <T> 克隆对象类型
* @return 被克隆出来的对象集合
* @see BeanCopierImpl#cloneList(Collection, Callback)
*/
public static <T> List<T> cloneList(Collection<T> sources, Callback<T, T> callback) {
return IMPL.cloneList(sources, callback);
return theCopier.cloneList(sources, callback);
}

/**
* {@link BeanCopierImpl#copyList(Collection, Class)}
* 批量拷贝对象
*
* @param sources 拷贝来源集合,不可以为 null。如果元素为 null 则拷贝出来的元素也为 null
* @param target 拷贝目标类
* @param <S> 拷贝来源类型
* @param <T> 拷贝目标类型
* @return 拷贝目标集合
* @see BeanCopierImpl#copyList(Collection, Class)
*/
public static <S, T> List<T> copyList(Collection<S> sources, Class<T> targetClass) {
return IMPL.copyList(sources, targetClass);
public static <S, T> List<T> copyList(Collection<S> sources, Class<T> target) {
return theCopier.copyList(sources, target);
}

/**
* {@link BeanCopierImpl#copyList(Collection, Class, Callback)}
*/
public static <S, T> List<T> copyList(Collection<S> source, Class<T> targetClass, Callback<S, T> callback) {
return IMPL.copyList(source, targetClass, callback);
* 批量拷贝对象,每一个对象拷贝完之后都会调用 callback
*
* @param source 拷贝来源集合,不可以为 null。如果元素为 null 则拷贝出来的元素也为 null
* @param target 拷贝目标类
* @param callback 回调
* @param <S> 拷贝来源类型
* @param <T> 拷贝目标类型
* @return 拷贝目标集合
* @see BeanCopierImpl#copyList(Collection, Class, Callback)
**/
public static <S, T> List<T> copyList(Collection<S> source, Class<T> target, Callback<S, T> callback) {
return theCopier.copyList(source, target, callback);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package io.github.tanyaofei.beancopier;


/**
* BeanCopier 全局配置
*
* @author tanyaofei
* @since 0.0.8
*/
public interface BeanCopierConfiguration {

/**
Expand Down
Loading

0 comments on commit 3dfcf6e

Please sign in to comment.