{"id":18050188,"url":"https://github.com/drtrang/copiers","last_synced_at":"2025-07-25T00:11:34.579Z","repository":{"id":87814029,"uuid":"70977148","full_name":"drtrang/Copiers","owner":"drtrang","description":"Friendly Bean Copy Tools.","archived":false,"fork":false,"pushed_at":"2018-08-01T08:29:17.000Z","size":218,"stargazers_count":51,"open_issues_count":2,"forks_count":18,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-24T11:21:39.523Z","etag":null,"topics":["beancopy","copier"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drtrang.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-10-15T08:53:28.000Z","updated_at":"2024-03-31T14:18:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"ad406403-1514-4744-8201-4a94be3794f0","html_url":"https://github.com/drtrang/Copiers","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drtrang%2FCopiers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drtrang%2FCopiers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drtrang%2FCopiers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drtrang%2FCopiers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drtrang","download_url":"https://codeload.github.com/drtrang/Copiers/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248217155,"owners_count":21066634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["beancopy","copier"],"created_at":"2024-10-30T21:10:53.037Z","updated_at":"2025-04-10T12:41:27.232Z","avatar_url":"https://github.com/drtrang.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Copiers\n\n[![Build Status](https://img.shields.io/travis/drtrang/Copiers/master.svg?style=flat-square)](https://www.travis-ci.org/drtrang/Copiers)\n[![Coverage Status](https://img.shields.io/coveralls/drtrang/Copiers/master.svg?style=flat-square)](https://coveralls.io/github/drtrang/Copiers?branch=master)\n[![Maven Central](https://img.shields.io/maven-central/v/com.github.drtrang/copiers.svg?style=flat-square)](https://maven-badges.herokuapp.com/maven-central/com.github.drtrang/copiers)\n[![GitHub Release](https://img.shields.io/github/release/drtrang/Copiers.svg?style=flat-square)](https://github.com/drtrang/Copiers/releases)\n[![License](http://img.shields.io/badge/license-apache%202-blue.svg?style=flat-square)](https://github.com/drtrang/Copiers/blob/master/LICENSE)\n\nCopiers 是一个优雅的 Bean 拷贝工具，可通过友好的 Fluent API 帮助用户完成拷贝对象的操作。\n\n## 依赖\n```xml\n\u003c!-- java8 or higher --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.drtrang\u003c/groupId\u003e\n    \u003cartifactId\u003ecopiers\u003c/artifactId\u003e\n    \u003cversion\u003e2.5.4\u003c/version\u003e\n\u003c/dependency\u003e\n\n\u003c!-- java7 --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.drtrang\u003c/groupId\u003e\n    \u003cartifactId\u003ecopiers\u003c/artifactId\u003e\n    \u003cversion\u003e1.4.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## 底层实现\nCopiers 目前有两种实现：`Cglib` \u0026 `Orika`，用户可以通过工厂方法来切换底层的拷贝方式。\n\n```java\n// orika\nCopiers.create(Class\u003cF\u003e sourceClass, Class\u003cT\u003e targetClass)\nCopiers.createOrika(Class\u003cF\u003e sourceClass, Class\u003cT\u003e targetClass)\n// cglib\nCopiers.createCglib(Class\u003cF\u003e sourceClass, Class\u003cT\u003e targetClass)\nCopiers.createCglib(Class\u003cF\u003e sourceClass, Class\u003cT\u003e targetClass, Converter converter)\n```\n\n### Cglib\nCglib 中的 BeanCopier 是目前性能最好的拷贝方式，基于 ASM 字节码增强技术，千万次拷贝仅需毫秒即可完成，但高性能带来的显著缺点是功能单一、拓展性差，BeanCopier 仅支持源对象到目标对象的**完全拷贝**，不支持自定义映射，Convert 拓展也只能对拷贝的 value 做处理，很多情况下不满足实际的业务需求。\n\n\u003e **注意：**\n\u003e 1. BeanCopier 只拷贝名称和类型都相同的属性\n\u003e 2. 当目标类的 setter 方法少于 getter 方法时，会导致创建 BeanCopier 失败\n\u003e 3. 一旦使用 Converter，BeanCopier 将完全使用 Converter 中定义的规则去拷贝，所以在 `convert()` 方法中要考虑到所有的属性，否则会抛出 `ClassCastException`\n\n### Orika\n[Orika](https://github.com/orika-mapper/orika) 基于 Javassist 字节码技术，千万次拷贝在 **5s** 左右。性能虽不如 Cglib，但 Orika 的优点在于灵活性、扩展性强，详细介绍可以查看 Orika 的 Github：https://github.com/orika-mapper/orika，另外强烈推荐这篇使用教程：http://www.baeldung.com/orika-mapping\n\n\u003e **注意：**\n\u003e 1. 拷贝结果为浅拷贝\n\u003e 2. 支持级联拷贝，但是需要提前注册好级联对象之间的映射关系，且可以使用 `parent()` 方法来指定父类\n\u003e 3. 支持源对象中的集合类型直接拷贝到目标对象的集合\n\u003e 4. 不同类型有默认的 Converter 做转换\n\n## 使用方式\n通过工厂方法建立 sourceClass 与 targetClass 之间的关系后，调用 `copy()` 方法即可完成 Bean 拷贝，调用 `copyList()` 方法即可完成 List 拷贝，简洁高效。\n\n### Cglib\n```java\n// 建立 User.class 与 UserEntity.class 之间的映射关系\nCopier copier = Copiers.createCglib(User.class, UserEntity.class);\n\n// 拷贝对象，创建新对象\nUser user = User.of(\"trang\", 25);\nUserEntity entity = copier.copy(user);\n\n// 拷贝对象，传入已有对象，完全拷贝\nUser user = User.of(\"trang\", null);\nUserEntity entity = UserEntity.of(\"meng\", 24);\ncopier.copy(user, entity);\n\n// 拷贝 List，创建新 List\nUser trang = User.of(\"trang\", 25);\nUser meng = User.of(\"meng\", 24);\nList\u003cUser\u003e family = ImmutableList.of(trang, meng);\nList\u003cUserEntity\u003e entries = copier.copyList(family);\n```\n\n### Orika\n```java\n// 建立 User.class 与 UserEntity.class 之间的映射关系\nCopier copier = Copiers.create(User.class, UserEntity.class);\n\n// 拷贝对象，创建新对象\nUser user = User.of(\"trang\", 25);\nUserEntity entity = copier.copy(user);\n\n// 拷贝对象，传入已有对象，不会拷贝值为 null 的属性（可以配置）\nUser user = User.of(\"trang\", null);\nUserEntity entity = UserEntity.of(\"meng\", 24);\ncopier.copy(user, entity);\n\n// 拷贝 List，创建新 List\nUser trang = User.of(\"trang\", 25);\nUser meng = User.of(\"meng\", 24);\nList\u003cUser\u003e family = ImmutableList.of(trang, meng);\nList\u003cUserEntity\u003e entries = copier.copyList(family);\n```\n\n## Orika 进阶\nOrika 支持强大的自定义关系映射，并且使用缓存技术，一次注册后续直接使用。\n\n```java\n// 跳过拷贝的属性，支持配置多个\n// Orika 默认使用全参构造，这时 skip() 不生效，需要使用不包含 skip 属性的构造方法，\n// 所以 Copiers 将默认值改为了无参构造，用户也可以在调用 skip() 后使用 constructor() 方法自己指定\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n        .skip(\"age\", \"sex\")\n        .register();\n\n// 将源对象的 `name` 属性映射到目标对象的 `username` 属性\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n        .field(\"name\", \"username\")\n        .register();\n\n// 开启拷贝 null 值，默认 Orika 不会将源对象中值为 null 的属性拷贝到目标对象中，如有需要可以手动开启\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n        .nulls()\n        .register();\n\n// 全局自定义映射关系，若和其它方法结合使用则在最后执行\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n        .customize(new CustomMapper\u003cUser, UserEntity\u003e() {\n            @Override\n            public void mapAtoB(User source, UserEntity target, MappingContext context) {\n                target.setUsername(\"prefix:\" + source.getName());\n            }\n        })\n        .register();\n```\n\n当然，以上映射关系可以任意搭配使用，同样只需一次注册。\n\n```java\n// 创建 copier\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n                // 跳过拷贝\n                .skip(\"age\", \"sex\")\n                // 自定义属性映射\n                .field(\"name\", \"username\")\n                // 全局自定义映射关系\n                .customize(new CustomMapper\u003cUser, UserEntity\u003e() {\n                    @Override\n                    public void mapAtoB(User source, UserEntity target, MappingContext context) {\n                        target.setUsername(\"prefix:\" + source.getName());\n                    }\n                })\n                .register();\n```\n\n如果你在使用 Java8 那就更好了，利用 Copiers 可以更容易的完成拷贝操作。\n\n```java\n// 创建 copier\nCopier\u003cUser, UserEntity\u003e copier = Copiers.createOrika(User.class, UserEntity.class)\n                .field(\"name\", \"username\")\n                .register();\n// 使用 Stream 拷贝 List\nsourceList.stream().map(copier::copy).collect(toList()); //copier.copyList(sourceList);\n// 使用并行 Stream 拷贝 List\nsourceList.parallelStream().map(copier::copy).collect(toList());\n// 使用 Optional 拷贝 List\nOptional.of(name)\n        .map(service::selectByName)\n        .map(copier::copyList) \n        .orElse(emptyList());\n```\n\n## Change Log\n[Release Notes](https://github.com/drtrang/Copiers/releases)\n\n## TODO\n任何意见和建议可以提 [ISSUE](https://github.com/drtrang/Copiers/issues)，我会酌情加到 [TODO List](https://github.com/drtrang/Copiers/blob/master/TODO.md)，一般情况一周内迭代完毕。\n\n## About Me\nQQ：349096849\u003cbr\u003e\nEmail：donghao.l@hotmail.com\u003cbr\u003e\nBlog：[Trang's Blog](http://blog.trang.space)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrtrang%2Fcopiers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrtrang%2Fcopiers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrtrang%2Fcopiers/lists"}