{"id":16409502,"url":"https://github.com/neoremind/easy-mapper","last_synced_at":"2026-02-19T10:31:56.715Z","repository":{"id":50284274,"uuid":"64106907","full_name":"neoremind/easy-mapper","owner":"neoremind","description":"Easy-mapper is a simple, light-weighted, high performance java bean mapping framework","archived":false,"fork":false,"pushed_at":"2023-07-11T04:56:46.000Z","size":143,"stargazers_count":114,"open_issues_count":7,"forks_count":34,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-07-21T10:14:43.347Z","etag":null,"topics":[],"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/neoremind.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-07-25T05:47:35.000Z","updated_at":"2025-04-07T23:19:35.000Z","dependencies_parsed_at":"2024-10-27T11:12:23.753Z","dependency_job_id":null,"html_url":"https://github.com/neoremind/easy-mapper","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/neoremind/easy-mapper","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoremind%2Feasy-mapper","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoremind%2Feasy-mapper/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoremind%2Feasy-mapper/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoremind%2Feasy-mapper/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neoremind","download_url":"https://codeload.github.com/neoremind/easy-mapper/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoremind%2Feasy-mapper/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29609815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T06:47:36.664Z","status":"ssl_error","status_checked_at":"2026-02-19T06:45:47.551Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-10-11T06:20:03.485Z","updated_at":"2026-02-19T10:31:56.698Z","avatar_url":"https://github.com/neoremind.png","language":"Java","funding_links":[],"categories":["Bean映射\u0026复制"],"sub_categories":[],"readme":"# Easy-mapper\n[![Build Status](https://travis-ci.org/neoremind/easy-mapper.svg?branch=master)](https://travis-ci.org/neoremind/easy-mapper)\n[![Coverage Status](https://coveralls.io/repos/github/neoremind/easy-mapper/badge.svg?branch=master)](https://coveralls.io/github/neoremind/easy-mapper?branch=master)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.baidu.unbiz/easy-mapper/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.baidu.unbiz/easy-mapper)\n[![Hex.pm](https://img.shields.io/hexpm/l/plug.svg)](http://www.apache.org/licenses/LICENSE-2.0)\n\nEasy-mapper is a simple, light-weighted, high-performance java bean mapping framework. By leveraging Javassist, easy mapper can generate mapping byte-code at runtime and load them into JVM for later invocations to reduce some of the overhead.\n\nEasy-mapper not only provides a relatively high-performance mapping solution, but also enables the caller to do mapping in a more flexible and extensible way. Fluent interface style API and Java8 lambda API, these modern techniques can be fully used to customize your own mapping strategy.\n\nHere, easy-mapper uses by-reference field mapping strategy most of the time except for some immutable types like primitive, wrapper, String and BigDecimal, etc. When you don’t need to copy and clone field, by-reference mapping is capable to process your business logic and avoid the overhead of performance loss. On the other hand, easy-mapper respects immutability and do not mean to offense, just provide an alternative solution.\n\nFor performance test result, please refer to the benchmark section.\n\n中文手册[请点这里](http://neoremind.com/2016/08/easy-mapper-%E4%B8%80%E4%B8%AA%E7%81%B5%E6%B4%BB%E5%8F%AF%E6%89%A9%E5%B1%95%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BDbean-mapping%E7%B1%BB%E5%BA%93/)。\n\n## 1. Easy-mapper in a nutshell\n### 1.1 Where to get easy mapper\nMaven:\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.baidu.unbiz\u003c/groupId\u003e\n    \u003cartifactId\u003eeasy-mapper\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\nGradle:\n```\ncompile 'com.baidu.unbiz:easy-mapper:1.0.4'\n```\n\n### 1.2 Develop Java bean\nPOJO:\n```\npublic class Person {\n    private String firstName;\n    private String lastName;\n    private List\u003cString\u003e jobTitles;\n    private long salary;\n    // getter and setter...\n}\n```\nDTO（Data Transfer Object）\n```\npublic class PersonDto {\n    private String firstName;\n    private String lastName;\n    private List\u003cString\u003e jobTitles;\n    private long salary;\n    // getter and setter...\n}\n```\n### 1.3 Start mapping\nFrom POJO to DTO:\n```\nPerson p = new Person();\np.setFirstName(\"NEO\");\np.setLastName(\"jason\");\np.setJobTitles(Lists.newArrayList(\"abc\", \"dfegg\", \"iii\"));\np.setSalary(1000L);\nPersonDto dto = MapperFactory.getCopyByRefMapper()\n                .mapClass(Person.class, PersonDto.class)\n                .registerAndMap(p, PersonDto.class);\nSystem.out.println(dto);\n```\n\n## 2. Dig into easy-mapper\n### 2.1 Register and map\nThere are two separate steps to do mapping and you can combine them.\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                .register()\n                .map(p, PersonDto.class);\n```\n\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                .register()\nMapper mapper = MapperFactory.getCopyByRefMapper();\nPersonDto dto = mapper.map(p, PersonDto.class);\n```\n\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                .register()\nMapper mapper = MapperFactory.getCopyByRefMapper().map(p, PersonDto.class);\n```\n\n### 2.2 Specify field name\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                .field(\"salary\", \"salary\")\n                .register()\n                .map(p, PersonDto.class);\n```\n\n### 2.3 Ignore fields from source object\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                .exclude(\"lastName\")\n                .register()\n                .map(p, PersonDto.class);\n```\n\n### 2.4 Customize filed mapping\n```\nPersonDto6 dto = new PersonDto6();\nMapperFactory.getCopyByRefMapper().mapClass(Person6.class, PersonDto6.class)\n        .field(\"jobTitles\", \"jobTitles\", new Transformer\u003cList\u003cString\u003e, List\u003cInteger\u003e\u003e() {\n            @Override\n            public List\u003cInteger\u003e transform(List\u003cString\u003e source) {\n                return Lists.newArrayList(1, 2, 3, 4);\n            }\n        })\n        .register()\n        .map(p, dto);\n```\n\nJava8 lambda:\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                    .field(\"firstName\", \"firstName\", (String s) -\u003e s.toLowerCase())\n                    .register()\n                    .map(p, PersonDto.class);\n```\n\nJava8 streaming:\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                    .field(\"jobTitles\", \"jobTitleLetterCounts\",\n                            (List\u003cString\u003e s) -\u003e s.stream().map(String::length).toArray(Integer[]::new))\n                    .register()\n                    .map(p, PersonDto.class);\n```\n\nType inference:\n```\nMapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                    .field(\"firstName\", \"firstName\", String.class, String.class, s -\u003e s.toLowerCase())\n                    .register()\n                    .map(p, PersonDto.class);\n```\n\n### 2.5 Customize object mapping\n```\nPersonDto6 dto = new PersonDto6();\nMapperFactory.getCopyByRefMapper().mapClass(Person6.class, PersonDto6.class)\n        .customMapping((a, b) -\u003e b.setLastName(a.getLastName().toUpperCase()))\n        .register()\n        .map(p, dto);\n```\n\n### 2.6 New object then mapping\n```\nPersonDto dto = new PersonDto();\nMapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class).registerAndMap(p, dto);\n```\n\n### 2.7 Map on null\n```\nPersonDto dto = MapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class)\n                    .mapOnNull(true)\n                    .register()\n                    .map(p, PersonDto.class);\n```\n\n### 2.8 Cascade mapping\nEasy-mapper can map recursively. If `Person` has-a `Address`, `Address` mapping should be done beforehand.\n```\nMapperFactory.getCopyByRefMapper().mapClass(Address.class, Address2.class).register();\nPerson p = getPerson(); \np.setAddress(new Address(\"beverly hill\", 10086));\nPersonDto dto = MapperFactory.getCopyByRefMapper()\n                    .mapClass(Person.class, PersonDto.class)\n                    .register()\n                    .map(p, PersonDto.class);\n```\nOtherwise there will result a exception like below:\n```\ncom.baidu.unbiz.easymapper.exception.MappingException: No class map found for (Address, Address2), make sure type or nested type is registered beforehand\n```\n\n### 2.9 Output generated source code for debugging\nSpecify the following args:\n```\n-Dcom.baidu.unbiz.easymapper.enableWriteSourceFile=true \n-Dcom.baidu.unbiz.easymapper.writeSourceFileAbsolutePath=\"...\"\n-Dcom.baidu.unbiz.easymapper.enableWriteClassFile=true \n-Dcom.baidu.unbiz.easymapper.writeClassFileAbsolutePath=\"...\"\n```\n\n## 3. Mapping rules\nRules prioritizes as below:\n\n1.\tCustom transformer goes with highest priority.\n\n2.\tField type is the same, copy by reference. For primitive and wrapper type, equal operator is used for assigning.\n\n3.\tIf target field is String but source is not, assign target with source.toString().\n\n4.\tIf target field type can be assigned from source field type, then **copy by reference**.\n\n5.\tAny other cases, use object graph or so called cascade mapping to map.\n\nAt last, if none of the mapping handlers work, there will end up with the following exception:\n```\ncom.baidu.unbiz.easymapper.exception.MappingCodeGenerationException: No appropriate mapping strategy found for FieldMap[jobTitles(List\u003cstring\u003e)--\u003ejobTitles(List\u003cinteger\u003e)]\n...\ncom.baidu.unbiz.easymapper.exception.MappingException: Generating mapping code failed for ClassMap([A]:Person6, [B]:PersonDto6), this should not happen, probably the framework could not handle mapping correctly based on your bean.\n```\n\nFor target class creation, it is OK without non-args default constructor, but you have to \nmake sure every parameter should be primitive or else easy-mapper cannot create an instance of the target class.\n\nEasy-mapper prefers default constructor to create the target class when multiple constructors appearing.\n\n## 4. Initialization\n\nSometimes the following exception will occur and program will never recover:\n```\nCaused by: com.baidu.unbiz.easymapper.exception.MappingException: No class map found for (String, String), make sure type or nested type is registered beforehand\n```\nThis is because during program startup, their might be concurrent calls, and `easy-mapper` relies on `SPI Service Provider` which is not thread-safe,\nso it fails the first time and never recover. In the long run, `SPI Service Provider` will be replaced. But currently what you can do is to paste the following code\nin your startup.\n\n```\nServiceLoaderHelper.getInstance();\n```\n\nFor example, in Spring context startup.\n```\npublic class CustomContextLoaderListener extends ContextLoaderListener {\n    static {\n        ServiceLoaderHelper.getInstance();\n    }\n}\n```\n\n## 5. Dependencies\n```\n+- org.slf4j:slf4j-api:jar:1.7.7:compile\n+- org.slf4j:slf4j-log4j12:jar:1.7.7:compile\n|  \\- log4j:log4j:jar:1.2.17:compile\n+- org.javassist:javassist:jar:3.18.1-GA:compile\n```\n\n## 6. Benchmark\nBased on Oracal Hotspot JVM:\n```\njava version \"1.8.0_51\"\nJava(TM) SE Runtime Environment (build 1.8.0_51-b16)\nJava HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)\n```\nJVM args:\n```\n-Xmx512m -Xms512m -XX:MetaspaceSize=256m\n```\nHardware configuration:\n```\nCPU: Intel(R) Core(TM) i5-4278U CPU @ 2.60GHz\nMEM: 8G\n```\n\nPlease refer to [testing source code](https://github.com/neoremind/easy-mapper/blob/master/src/test/java/com/baidu/unbiz/easymapper/performance/BenchmarkTest.java).\n```\n-------------------------------------\n| Create object number:   10000      |\n-------------------------------------\n|     Framework     |    time cost   |\n-------------------------------------\n|      Pure get/set |      11ms      |\n|       Easy mapper |      44ms      |\n|  Cglib beancopier |       7ms      |\n|         BeanUtils |     248ms      |\n|     PropertyUtils |     129ms      |\n|  Spring BeanUtils |      95ms      |\n|             Dozer |     772ms      |\n-------------------------------------\n-------------------------------------\n| Create object number:  100000      |\n-------------------------------------\n|     Framework     |    time cost   |\n-------------------------------------\n|      Pure get/set |      56ms      |\n|       Easy mapper |     165ms      |\n|  Cglib beancopier |      30ms      |\n|         BeanUtils |     921ms      |\n|     PropertyUtils |     358ms      |\n|  Spring BeanUtils |     152ms      |\n|             Dozer |    1224ms      |\n-------------------------------------\n-------------------------------------\n| Create object number: 1000000      |\n-------------------------------------\n|     Framework     |    time cost   |\n-------------------------------------\n|      Pure get/set |     189ms      |\n|       Easy mapper |     554ms      |\n|  Cglib beancopier |      48ms      |\n|         BeanUtils |    4210ms      |\n|     PropertyUtils |    4386ms      |\n|  Spring BeanUtils |     367ms      |\n|             Dozer |    6319ms      |\n-------------------------------------\n```\n\nConclusion:\n\nEasy-mapper is way faster than traditional framework like Apache BeanUtils, PropertyUtils and dozer but cannot beat Cglib Beancopier which manipulating byte code using ASM directly. \n\nFor Spring BeanUtils, when invocation number exceeds certain threshold, Spring BeanUtils is faster than Easy-mapper. That is because Spring BeanUtils is so simple that it just execute Method.invoke(..), and this reflection work can be improved by JIT compiler at runtime and does not invoke native method. \n\nBy thinking of the benefits that easy-mapper brings to you, this tradeoff can be accepted.\n\n## 7. Working together with High-order function\n### 7.1 With guava\n```\nMapperFactory.getCopyByRefMapper().mapClass(Address.class, Address2.class).register();\nMapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class).register();\nList\u003cPerson\u003e personList = getPersonList();\nCollection\u003cPersonDto\u003e personDtoList = Collections2.transform(personList,\n        p -\u003e MapperFactory.getCopyByRefMapper().map(p, PersonDto.class));\nSystem.out.println(personDtoList);\n```\n\n### 7.2 With functional java\n```\nMapperFactory.getCopyByRefMapper().mapClass(Address.class, Address2.class).register();\nMapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class).register();\nList\u003cPerson\u003e personList = getPersonList();\nfj.data.List\u003cPersonDto\u003e personDtoList = fj.data.List.fromIterator(personList.iterator()).map(\n        person -\u003e MapperFactory.getCopyByRefMapper().map(person, PersonDto.class));\npersonDtoList.forEach(e -\u003e System.out.println(e));\n```\n\n### 7.3 With Java8 stream\n```\nMapperFactory.getCopyByRefMapper().mapClass(Address.class, Address2.class).register();\nMapperFactory.getCopyByRefMapper().mapClass(Person.class, PersonDto.class).register();\nList\u003cPerson\u003e personList = getPersonList();\nList\u003cPersonDto\u003e personDtoList = personList.stream().map(p -\u003e MapperFactory.getCopyByRefMapper().map(p,\n        PersonDto.class)).collect(Collectors.toList());\n```\n\n\n### 7.4 With Scala\n```\nobject EasyMapperTest {\n \n  def main(args: Array[String]) {\n    MapperFactory.getCopyByRefMapper.mapClass(classOf[Person], classOf[PersonDto]).register\n    val personList = List(\n      new Person(\"neo1\", 100),\n      new Person(\"neo2\", 200),\n      new Person(\"neo3\", 300)\n    )\n    val personDtoList = personList.map(p =\u003e MapperFactory.getCopyByRefMapper.map(p, classOf[PersonDto]))\n    personDtoList.foreach(println)\n  }\n}\n```\n\n## 8. Acknowledgment\nThe development of easy-mapper is inspired by Orika. Easy-mapper with Apache2.0 Open Source License retains all copyright, trademark, author’s information from Orika.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneoremind%2Feasy-mapper","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneoremind%2Feasy-mapper","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneoremind%2Feasy-mapper/lists"}