{"id":26534810,"url":"https://github.com/expediagroup/bull","last_synced_at":"2026-01-11T17:38:06.280Z","repository":{"id":38201211,"uuid":"166023376","full_name":"ExpediaGroup/bull","owner":"ExpediaGroup","description":"BULL - Bean Utils Light Library","archived":false,"fork":false,"pushed_at":"2024-04-12T07:58:08.000Z","size":25132,"stargazers_count":182,"open_issues_count":2,"forks_count":45,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-04-12T15:12:54.600Z","etag":null,"topics":["beancopy","beanutils","bull","hacktoberfest","immutable-objects","java","java-bean","mapper","mapping","mutable","oss-portal-featured","transformation","transformations"],"latest_commit_sha":null,"homepage":"https://opensource.expediagroup.com/bull","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/ExpediaGroup.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG-JDK11.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-01-16T10:46:08.000Z","updated_at":"2024-04-15T13:47:38.050Z","dependencies_parsed_at":"2024-02-05T14:46:21.711Z","dependency_job_id":"28018dd2-059a-4ac9-9655-93c8d5436f72","html_url":"https://github.com/ExpediaGroup/bull","commit_stats":null,"previous_names":["hotelsdotcom/bull"],"tags_count":132,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpediaGroup%2Fbull","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpediaGroup%2Fbull/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpediaGroup%2Fbull/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ExpediaGroup%2Fbull/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ExpediaGroup","download_url":"https://codeload.github.com/ExpediaGroup/bull/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247635091,"owners_count":20970668,"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","beanutils","bull","hacktoberfest","immutable-objects","java","java-bean","mapper","mapping","mutable","oss-portal-featured","transformation","transformations"],"created_at":"2025-03-21T20:20:24.784Z","updated_at":"2026-01-11T17:38:06.271Z","avatar_url":"https://github.com/ExpediaGroup.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1\u003e\n  \u003cimg width=\"420\" alt=\"BULL\" src=\"./docs/site/resources/images/BullBranding_04.png\"\u003e\n\u003c/h1\u003e\n\n## Bean Utils Light Library\n\nBULL is a Java Bean to Java Bean transformer that recursively copies data from one object to another, it is generic, flexible, reusable, configurable, and incredibly fast.\nIt's the only library able to transform Mutable, Immutable, and Mixed bean without any custom configuration.\n\n## Start using\n\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.expediagroup.beans/bull-bean-transformer/badge.svg?subject=maven-central\u0026color=blue)](https://maven-badges.herokuapp.com/maven-central/com.expediagroup.beans/bull-bean-transformer)\n[![Javadocs](http://www.javadoc.io/badge/com.expediagroup.beans/bull-bean-transformer.svg?color=blue)](http://www.javadoc.io/doc/com.expediagroup.beans/bull-bean-transformer)\n[![Build Status](https://github.com/ExpediaGroup/bull/actions/workflows/github-default-actions.yml/badge.svg?branch=master)](https://github.com/ExpediaGroup/bull/actions)\n[![Join the chat at https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk](https://img.shields.io/badge/Slack-%23bull-ECB22E.svg?logo=data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTQgNTQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTkuNzEyLjEzM2E1LjM4MSA1LjM4MSAwIDAgMC01LjM3NiA1LjM4NyA1LjM4MSA1LjM4MSAwIDAgMCA1LjM3NiA1LjM4Nmg1LjM3NlY1LjUyQTUuMzgxIDUuMzgxIDAgMCAwIDE5LjcxMi4xMzNtMCAxNC4zNjVINS4zNzZBNS4zODEgNS4zODEgMCAwIDAgMCAxOS44ODRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYgNS4zODdoMTQuMzM2YTUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2LTUuMzg3IDUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2LTUuMzg2IiBmaWxsPSIjMzZDNUYwIi8+PHBhdGggZD0iTTUzLjc2IDE5Ljg4NGE1LjM4MSA1LjM4MSAwIDAgMC01LjM3Ni01LjM4NiA1LjM4MSA1LjM4MSAwIDAgMC01LjM3NiA1LjM4NnY1LjM4N2g1LjM3NmE1LjM4MSA1LjM4MSAwIDAgMCA1LjM3Ni01LjM4N20tMTQuMzM2IDBWNS41MkE1LjM4MSA1LjM4MSAwIDAgMCAzNC4wNDguMTMzYTUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2IDUuMzg3djE0LjM2NGE1LjM4MSA1LjM4MSAwIDAgMCA1LjM3NiA1LjM4NyA1LjM4MSA1LjM4MSAwIDAgMCA1LjM3Ni01LjM4NyIgZmlsbD0iIzJFQjY3RCIvPjxwYXRoIGQ9Ik0zNC4wNDggNTRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODcgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODZoLTUuMzc2djUuMzg2QTUuMzgxIDUuMzgxIDAgMCAwIDM0LjA0OCA1NG0wLTE0LjM2NWgxNC4zMzZhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODYgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODdIMzQuMDQ4YTUuMzgxIDUuMzgxIDAgMCAwLTUuMzc2IDUuMzg3IDUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2IDUuMzg2IiBmaWxsPSIjRUNCMjJFIi8+PHBhdGggZD0iTTAgMzQuMjQ5YTUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2IDUuMzg2IDUuMzgxIDUuMzgxIDAgMCAwIDUuMzc2LTUuMzg2di01LjM4N0g1LjM3NkE1LjM4MSA1LjM4MSAwIDAgMCAwIDM0LjI1bTE0LjMzNi0uMDAxdjE0LjM2NEE1LjM4MSA1LjM4MSAwIDAgMCAxOS43MTIgNTRhNS4zODEgNS4zODEgMCAwIDAgNS4zNzYtNS4zODdWMzQuMjVhNS4zODEgNS4zODEgMCAwIDAtNS4zNzYtNS4zODcgNS4zODEgNS4zODEgMCAwIDAtNS4zNzYgNS4zODciIGZpbGw9IiNFMDFFNUEiLz48L2c+PC9zdmc+\u0026labelColor=611f69)](https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk)\n\n[![GitHub site](https://img.shields.io/badge/GitHub-site-blue.svg)](https://opensource.expediagroup.com/bull/)\n[![Coverage Status](https://coveralls.io/repos/github/ExpediaGroup/bull/badge.svg?branch=master)](https://coveralls.io/github/ExpediaGroup/bull?branch=master)\n[![License](https://img.shields.io/github/license/ExpediaGroup/bull.svg)](https://img.shields.io/github/license/ExpediaGroup/bull.svg)\n[![Dependabot](https://img.shields.io/badge/dependabot-enabled-success?logo=dependabot)](https://img.shields.io/badge/dependabot-enabled-success?logo=dependabot)\n\nA tutorial that integrates the library can be found [here](https://github.com/fborriello/bull-tutorial).\n\nAll BULL modules are available on Maven Central:\n\n* ### Bean BOM\n\nIt contains all the modules available in the project\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.expediagroup.beans\u003c/groupId\u003e\n    \u003cartifactId\u003ebull-bom\u003c/artifactId\u003e\n    \u003cversion\u003ex.y.z\u003c/version\u003e\n    \u003ctype\u003epom\u003c/type\u003e\n    \u003cscope\u003eimport\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n* ### Bean Transformer\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.expediagroup.beans\u003c/groupId\u003e\n    \u003cartifactId\u003ebull-bean-transformer\u003c/artifactId\u003e\n    \u003cversion\u003ex.y.z\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n* ### `Map` Transformer\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.expediagroup.beans\u003c/groupId\u003e\n    \u003cartifactId\u003ebull-map-transformer\u003c/artifactId\u003e\n    \u003cversion\u003ex.y.z\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**The project provides two different builds**, one compatible with `jdk 8` (or above),\none with `jdk 11` and on with `jdk 17` or above.\n\nIn case you need to integrate it in a:\n* `jdk 8` please refer to [CHANGELOG-JDK8](CHANGELOG-JDK8.md)\n* `jdk 11` please refer to [CHANGELOG-JDK11](CHANGELOG-JDK11.md)\n* `jdk 15` [CHANGELOG](CHANGELOG.md)\n\n* #### Suggestions\n\nSome jdk versions remove the Java Bean constructor's argument names from the compiled code and this may cause problems to the library.\nOn top of that, it's suggested to configure the `maven-compiler-plugin`, inside your project, as follow:\n\n```xml\n\u003cbuild\u003e\n    ...\n    \u003cpluginManagement\u003e\n        \u003cplugins\u003e\n            ...\n            \u003cplugin\u003e\n                \u003cgroupId\u003eorg.apache.maven.plugins\u003c/groupId\u003e\n                \u003cartifactId\u003emaven-compiler-plugin\u003c/artifactId\u003e\n                \u003cversion\u003e${maven.compiler.plugin.version}\u003c/version\u003e\n                \u003cconfiguration\u003e\n                    \u003csource\u003e${maven.compiler.source}\u003c/source\u003e\n                    \u003ctarget\u003e${maven.compiler.target}\u003c/target\u003e\n                    \u003cparameters\u003etrue\u003c/parameters\u003e\n                    \u003cforceJavacCompilerUse\u003etrue\u003c/forceJavacCompilerUse\u003e\n                \u003c/configuration\u003e\n            \u003c/plugin\u003e\n        \u003c/plugins\u003e\n    \u003c/pluginManagement\u003e\n    ...\n\u003c/build\u003e\n```\n\n## Maven build\n\nFull build\n\n```shell script\n./mvnw clean install\n```\nor on Windows\n\n```shell script\nmvnw.cmd clean install\n```\n\n### Skip test coverage and checkstyle check\n\n```shell script\n./mvnw clean install -P relaxed\n```\n\nor on Windows\n\n```shell script\nmvnw.cmd clean install -P relaxed\n```\n\n### Check for dependencies update\n\n```\nmvn versions:display-dependency-updates -P check-for-updates\n```\n\nor on Windows\n\n```shell script\nmvnw.cmd versions:display-dependency-updates -P check-for-updates\n```\n\n## Features:\n* support copy of immutable beans.\n* support copy of mutable beans.\n* support copy of hybrid beans (some fields private and some not).\n* support copy of Java Records.\n* support copy of Java beans without getter and setter methods.\n* support copy with Java primitive type.\n* support copy with Java Collection type. e.g. `List\u003cBeanA\u003e =\u003e List\u003cBeanB\u003e`\n* support copy with nested map fields. e.g. `Map\u003cString, Map\u003cString, String\u003e\u003e`\n* support copy with array containing primitive types. e.g. `String[]` =\u003e `String[]`\n* support copy with an array type. e.g. `BeanA[]` =\u003e `BeanB[]`\n* support copy with property name mapping. e.g. `int id =\u003e int userId`\n* support copy with recursion copy.\n* support validation through annotations.\n* support copy of beans with different field's name.\n* support lambda function field transformation.\n* support copy of java bean built through Builder.\n* easy usage, declarative way to define the property mapping (in case of different names), or simply adding the Lombok annotations.\n* allows setting the default value for all objects not existing in the source object.\n* allows skipping transformation for a given set of fields.\n* supports the retrieval of the value from getters if a field does not exist in the source object.\n* supports the automatic conversion of primitive types.\n\n# Feature samples\n\n* [Bean Transformation](https://github.com/ExpediaGroup/bull#bean-transformation-samples)\n* [Bean Validation](https://github.com/ExpediaGroup/bull#validation-samples)\n* [Primitive Type conversion](https://github.com/ExpediaGroup/bull#primitive-type-object-converter)\n* [Map Transformation](https://opensource.expediagroup.com/bull/transformer/map/samples.html)\n* [Supported Builder Pattern](https://opensource.expediagroup.com/bull/transformer/bean/builder.html)\n* [How to use it in Kotlin](https://opensource.expediagroup.com/bull/kotlin.html)\n\n## Bean transformation samples\n\n### Simple case:\n\n```java\npublic class FromBean {                                     public class ToBean {\n    private final String name;                                  @NotNull\n    private final BigInteger id;                                public BigInteger id;\n    private final List\u003cFromSubBean\u003e subBeanList;                private final String name;\n    private List\u003cString\u003e list;                                  private final List\u003cString\u003e list;\n    private final FromSubBean subObject;                        private final List\u003cToSubBean\u003e subBeanList;\n    private ImmutableToSubFoo subObject;\n\n    // all constructors                                         // all args constructor\n    // getters and setters...                                   // getters and setters... \n}    \n```\nAnd one line code as:\n```java\nToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);\n```\n\n### Different field names copy:\n\nFrom class and To class with different field names:\n```java\npublic class FromBean {                                     public class ToBean {\n\n    private final String name;                                  private final String differentName;\n    private final int id;                                       private final int id;\n    private final List\u003cFromSubBean\u003e subBeanList;                private final List\u003cToSubBean\u003e subBeanList;\n    private final List\u003cString\u003e list;                            private final List\u003cString\u003e list;\n    private final FromSubBean subObject;                        private final ToSubBean subObject;\n\n    // getters...\n    public ToBean(final String differentName,\n                  final int id,\n}                                                                       final List\u003cToSubBean\u003e subBeanList,\n    final List\u003cString\u003e list,\n    final ToSubBean subObject) {\n        this.differentName = differentName;\n        this.id = id;\n        this.subBeanList = subBeanList;\n        this.list = list;\n        this.subObject = subObject;\n    }\n\n    // getters...           \n\n}\n```\nAnd one line code as:\n\n```java                                                                \nbeanUtils.getTransformer().withFieldMapping(new FieldMapping\u003c\u003e(\"name\", \"differentName\")).transform(fromBean, ToBean.class);                                                               \n```\n\nit is also possible to map a field in the source class into multiple fields in the destination object.\n\nGiven the following source class:\n\n```\npublic class SourceClass {\n    private final String name;\n    private final int id;\n}\n```\n\nthe following destination class:\n\n```\npublic class DestinationClass {\n    private final String name;\n    private final int id;\n    private final int index;\n}\n``` \n\nand the following operations:\n\n```\nvar sourceObj = new SourceClass(\"foo\", 123);\n\nvar multipleFieldMapping = new FieldMapping\u003c\u003e(\"id\", \"index\", \"identifier\");\n\nvar destObj = new BeanUtils().getBeanTransformer()\n                     .withFieldMapping(multipleFieldMapping)\n                     .transform(sourceObj, DestinationClass.class);\n\nSystem.out.println(\"name = \" + destObj.getName());\nSystem.out.println(\"id = \" + destObj.getId());\nSystem.out.println(\"index = \" + destObj.getIndex());\n``` \n\nthe output will be:\n\n```\nname = foo\nid = 123\nindex = 123\n```\n\n\n### Mapping destination fields with correspondent fields contained inside one of the nested objects in the source object:\n\nAssuming that the object `FromSubBean` is declared as follow:\n```java\npublic class FromSubBean {\n\n    private String serialNumber;\n    private Date creationDate;\n\n    // getters and setters... \n\n}\n```\nand our source object and destination object are described as follow:\n```java\npublic class FromBean {                                     public class ToBean {\n\n    private final int id;                                       private final int id;\n    private final String name;                                  private final String name;\n    private final FromSubBean subObject;                        private final String serialNumber;\n    private final Date creationDate;\n\n    // all args constructor                                     // all args constructor\n    // getters...                                               // getters... \n\n}                                                           }\n```\nthe fields: `serialNumber` and `creationDate` needs to be retrieved from `subObject`, this can be done by defining the whole path to the end property:\n```java  \nFieldMapping serialNumberMapping = new FieldMapping\u003c\u003e(\"subObject.serialNumber\", \"serialNumber\");                                                             \nFieldMapping creationDateMapping = new FieldMapping\u003c\u003e(\"subObject.creationDate\", \"creationDate\");\n                                                             \nbeanUtils.getTransformer()\n         .withFieldMapping(serialNumberMapping, creationDateMapping)\n         .transform(fromBean, ToBean.class);                                                               \n```\n\n### Different field names defining constructor args:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private final String differentName;                   \n   private final int id;                                       private final int id;                      \n   private final List\u003cFromSubBean\u003e subBeanList;                private final List\u003cToSubBean\u003e subBeanList;                 \n   private final List\u003cString\u003e list;                            private final List\u003cString\u003e list;                    \n   private final FromSubBean subObject;                        private final ToSubBean subObject;                    \n   \n   // all args constructor\n   // getters...\n                                                               public ToBean(@ConstructorArg(\"name\") final String differentName, \n                                                                        @ConstructorArg(\"id\") final int id,\n}                                                                       @ConstructorArg(\"subBeanList\") final List\u003cToSubBean\u003e subBeanList,\n                                                                        @ConstructorArg(fieldName =\"list\") final List\u003cString\u003e list,\n                                                                        @ConstructorArg(\"subObject\") final ToSubBean subObject) {\n                                                                        this.differentName = differentName;\n                                                                        this.id = id;\n                                                                        this.subBeanList = subBeanList;\n                                                                        this.list = list;\n                                                                        this.subObject = subObject; \n                                                                    }\n                                                                \n                                                                    // getters...           \n                                              \n                                                            }\n```\nAnd one line code as:\n```java\nToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);\n```\n\n### Different field names and types applying transformation through lambda function:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  @NotNull                   \n   private final BigInteger id;                                public BigInteger identifier;                      \n   private final BigInteger index;                             public BigInteger index;                      \n   private final List\u003cFromSubBean\u003e subBeanList;                private final String name;                 \n   private List\u003cString\u003e list;                                  private final List\u003cString\u003e list;                    \n   private final FromSubBean subObject;                        private final List\u003cImmutableToSubFoo\u003e nestedObjectList;                    \n   private final String locale;                                private final Locale locale;                    \n                                                               private ImmutableToSubFoo nestedObject;\n       \n   // constructors...                                          // constructors...\n   // getters and setters...                                   // getters and setters...\n                                                                                                                              \n}                                                           }\n```\n\n```java\nFieldTransformer\u003cBigInteger, BigInteger\u003e fieldTransformer = new FieldTransformer\u003c\u003e(\"identifier\", BigInteger::negate);\nFieldTransformer\u003cString, Locale\u003e localeTransformer = new FieldTransformer\u003c\u003e(\"locale\", Locale::forLanguageTag);\nbeanUtils.getTransformer()\n    .withFieldMapping(new FieldMapping\u003c\u003e(\"id\", \"identifier\"))\n    .withFieldTransformer(fieldTransformer).transform(fromBean, ToBean.class)\n    .withFieldTransformer(localeTransformer);\n```\n\nIt's also possible to apply the same transformation function on multiple fields. Taking as an example the above bean and\nassuming that we would negate both the id and the identifier, the transformer function has to be defined as follows:\n\n```java\nFieldTransformer\u003cBigInteger, BigInteger\u003e fieldTransformer = new FieldTransformer\u003c\u003e(List.of(\"identifier\", \"index\"), BigInteger::negate);\n```\n\n### Assign a default value in case of missing field in the source object:\n\nAssign a default value in case of a missing field in the source object:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  @NotNull                   \n   private final BigInteger id;                                public BigInteger id;                      \n                                                               private final String name;                 \n                                                               private String notExistingField; // this will be null and no exceptions will be raised\n\n   // constructors...                                          // constructors...\n   // getters...                                               // getters and setters...\n\n}                                                           }\n```\nAnd one line code as:\n```java\nToBean toBean = beanUtils.getTransformer()\n                    .setDefaultValueForMissingField(true).transform(fromBean, ToBean.class);\n```\n\n### Disable the default value set for primitive types in case they are null:\n\nBULL by default sets the default value for all primitive types fields in case their value is in the source object.\nGiven the following Java Bean:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  @NotNull                   \n   private final BigInteger id;                                public BigInteger id;                      \n                                                               private final String name;                 \n\n   // constructors...                                          // constructors...\n   // getters...                                               // getters and setters...\n\n}                                                           }\n```\n\nin case the field `id` in the `FromBean` object is `null`, the value assigned the correspondent field in the `ToBean` object will be `0`.\nTo disable this you can simply do:\n\n```java\nToBean toBean = beanUtils.getTransformer()\n                    .setDefaultValueForMissingPrimitiveField(false).transform(fromBean, ToBean.class);\n```\n\nin this case, the field `id` after the transformation will be `null`\n\n### Applying a transformation function in case of missing fields in the source object:\n\nAssign a default value in case of a missing field in the source object:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  @NotNull                   \n   private final BigInteger id;                                public BigInteger id;                      \n                                                               private final String name;                 \n                                                               private String notExistingField; // this will have value: sampleVal\n                                                               \n   // all args constructor                                     // constructors...\n   // getters...                                               // getters and setters...\n}                                                           }\n```\nAnd one line code as:\n```java\nFieldTransformer\u003cString, String\u003e notExistingFieldTransformer = new FieldTransformer\u003c\u003e(\"notExistingField\", () -\u003e \"sampleVal\");\nToBean toBean = beanUtils.getTransformer()\n                    .withFieldTransformer(notExistingFieldTransformer)\n                    .transform(fromBean, ToBean.class);\n```\n\n### Apply a transformation function on a field contained in a nested object:\n\nThis example shows how a lambda transformation function can be applied to a nested object field.\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private final String name;                   \n   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    \n\n   // all args constructor                                     // all args constructor\n   // getters...                                               // getters...\n}                                                           }\n```\nand\n```java\npublic class ToSubBean {                           \n   private final String name;                   \n   private final long index;                    \n}\n```\nAssuming that the lambda transformation function should be applied only to field: `name` contained into the `ToSubBean` object, the transformation function has to be defined as\nfollow:\n```java\nFieldTransformer\u003cString, String\u003e nameTransformer = new FieldTransformer\u003c\u003e(\"nestedObject.name\", StringUtils::capitalize);\nToBean toBean = beanUtils.getTransformer()\n                    .withFieldTransformer(nameTransformer)\n                    .transform(fromBean, ToBean.class);\n```\n\n### Map a primitive type field in the source object into a nested object:\n\nThis example shows how to map a primitive field into a nested object into the destination one.\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private final String name;                   \n   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    \n   private final int x;\n   // all args constructor                                     // all args constructor\n   // getters...                                               // getters...\n}                                                           }\n```\nand\n```java\npublic class ToSubBean {                           \n   private final int x;\n   \n   // all args constructor\n}  // getters...          \n```\nAssuming that the value `x` should be mapped into the field: `x` contained into the `ToSubBean` object, the field mapping has to be defined as\nfollow:\n```java\nToBean toBean = beanUtils.getTransformer()\n                    .withFieldMapping(new FieldMapping\u003c\u003e(\"x\", \"nestedObject.x\"));\n```\n\n### Apply a transformation function on all fields matching with the given one:\n\nThis example shows how a lambda transformation function can be applied to all fields matching with the given one independently from their position.\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private final String name;                   \n   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    \n\n   // all args constructor                                     // all args constructor\n   // getters...                                               // getters...\n}                                                           }\n```\nand\n```java\npublic class FromSubBean {                                  public class ToSubBean {                           \n   private final String name;                                  private final String name;                   \n   private final long index;                                   private final long index;                    \n   \n   // all args constructor                                     // all args constructor\n   // getters...                                               // getters...\n}                                                           }\n```\nAssuming that the lambda transformation function should be applied only to the field: `name` contained in the `ToSubBean` object, the transformation function has to be defined\nas\nfollow:\n```java\nFieldTransformer\u003cString, String\u003e nameTransformer = new FieldTransformer\u003c\u003e(\"name\", StringUtils::capitalize);\nToBean toBean = beanUtils.getTransformer()\n                    .setFlatFieldNameTransformation(true)\n                    .withFieldTransformer(nameTransformer)\n                    .transform(fromBean, ToBean.class);\n```\n\n### Static transformer function:\n\n```java\nList\u003cFromFooSimple\u003e fromFooSimpleList = Arrays.asList(fromFooSimple, fromFooSimple);\n```\ncan be transformed as follow:\n```java\nFunction\u003cFromFooSimple, ImmutableToFooSimple\u003e transformerFunction = BeanUtils.getTransformer(ImmutableToFooSimple.class);\nList\u003cImmutableToFooSimple\u003e actual = fromFooSimpleList.stream()\n                .map(transformerFunction)\n                .collect(Collectors.toList());\n```\nor if you have a pre-configured transformer:\n```java\nFunction\u003cFromFooSimple, ImmutableToFooSimple\u003e transformerFunction = BeanUtils.getTransformer(\u003cyourPreconfiguredTransformer\u003e, ImmutableToFooSimple.class);\nList\u003cImmutableToFooSimple\u003e actual = fromFooSimpleList.stream()\n                .map(transformerFunction)\n                .collect(Collectors.toList());\n```\n\n### Enable Java Beans validation:\n\nAssuming that the field: `id` in the fromBean instance is null.\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  @NotNull                   \n   private final BigInteger id;                                public BigInteger id;                      \n                                                               private final String name;\n\n   // all args constructor                                     // all args constructor\n   // getters...                                               // getters and setters...\n}                                                            }\n```\nadding the following configuration an exception will be thrown:\n```java\nToBean toBean = beanUtils.getTransformer()\n                     .setValidationEnabled(true)\n                     .transform(fromBean, ToBean.class);\n```\n\n### Copy on an existing instance:\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private String name;                   \n   private final FromSubBean nestedObject;                     private ToSubBean nestedObject;                    \n\n   // all args constructor                                     // constructor\n   // getters...                                               // getters and setters...\n}                                                           }\n```\nif you need to perform the copy on an already existing object, just do:\n```java\nToBean toBean = new ToBean();\nbeanUtils.getTransformer().transform(fromBean, toBean);\n```\n\n### Skip transformation on a given set of fields:\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private String name;                   \n   private final FromSubBean nestedObject;                     private ToSubBean nestedObject;                    \n\n   // all args constructor                                     // constructor\n   // getters...                                               // getters and setters...\n}                                                           }\n\npublic class FromBean2 {                   \n   private final int index;             \n   private final FromSubBean nestedObject;\n                                          \n   // all args constructor                \n   // getters...                          \n}                                         \n```\nif you need to skip the transformation for a given field, just do:\n```java\nToBean toBean = new ToBean();\nbeanUtils.getTransformer()\n    .skipTransformationForField(\"nestedObject\")\n    .transform(fromBean, toBean);\n```\n\nwhere `nestedObject` is the name of the field in the destination object.\n\nThis feature allows us to **transform an object keeping the data from different sources**.\n\nTo better explain this function let's assume that the `ToBean` (defined above) should be transformed as follow:\n- `name` field value has been taken from the `FromBean` object\n- `nestedObject` field value has been taken from the `FromBean2` object\n\nthe objective can be reached by doing:\n```java\n// create the destination object\nToBean toBean = new ToBean();\n\n// execute the first transformation skipping the copy of: 'nestedObject' field that should come from the other source object\nbeanUtils.getTransformer()\n    .skipTransformationForField(\"nestedObject\")\n    .transform(fromBean, toBean);\n\n// then execute the transformation skipping the copy of: 'name' field that should come from the other source object\nbeanUtils.getTransformer()\n    .skipTransformationForField(\"name\")\n    .transform(fromBean2, toBean);\n```\n\n### Keep a field type value from the source object as is:\n\nGiven:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String name;                                  private String name;                   \n   private final DateTime dateTime;                            private final DateTime dateTime;              \n\n   // all args constructor                                     // constructor\n   // getters...                                               // getters and setters...\n}                                                           }\n```\n\nif you need to keep the value of a field type from the source object as it, you can add all the types you want to keep as they are\nby doing:\n\n```java\nClassUtils.CUSTOM_SPECIAL_TYPES.add(DateTime.class);\n\nToBean toBean = new ToBean();\nbeanUtils.getTransformer()\n    .transform(fromBean, toBean);\n```\n\n### Not existing field in the source object:\nIn case the destination class has a field that does not exist in the source object, but it contains a getter method returning the value, the library should gets the field value from that method.\n```java\npublic class FromBean {                                     public class ToBean {                           \n                                                               private final BigInteger id;\n    public BigInteger getId() {                                   \n        return BigInteger.TEN;                                 // all args constructor\n   }                                                           // getters...\n}                                                               \n                                                            }\n```\nAnd one line code as:\n```java\nToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);\n```\n\n### Transform primitive types automatically\n\nGiven the following Java Bean:\n\n```java\npublic class FromBean {                                     public class ToBean {                           \n   private final String indexNumber;                           private final int indexNumber;                                 \n   private final BigInteger id;                                public Long id;                      \n\n   // constructors...                                          // constructors...\n   // getters...                                               // getters and setters...\n\n}                                                           }\n```\n\nas, by default the primitive type conversion is disabled, to get the above object converted we should have\nimplemented transformer functions for both field `indexNumber` and `id`, but this can be done automatically by enabling the\nthe functionality described above.\n\n```java\nTransformer transformer = beanUtils.getTransformer()\n                             .setPrimitiveTypeConversionEnabled(true);\n\nToBean toBean = transformer.transform(fromBean, ToBean.class);\n```\n\n**IMPORTANT:** The primitive type transformation (if enabled) is executed before any other `FieldTransformer` function is defined on a specific field.\nThis means that once the `FieldTransformer` function will be executed the field value has already been transformed.\n\n## Builder supported patterns\n\nThe library supports the transformation of Java Bean using the following Builder patterns:\n\n### Standard pattern:\n\n```java\npublic class ItemType {\n    private final Class\u003c?\u003e objectClass;\n    private final Class\u003c?\u003e genericClass;\n\n    ItemType(final Class\u003c?\u003e objectClass, final Class\u003c?\u003e genericClass) {\n        this.objectClass = objectClass;\n        this.genericClass = genericClass;\n    }\n\n    public static ItemTypeBuilder builder() {\n        return new ItemType.ItemTypeBuilder();\n    }\n\n    // getter methods\n\n    public static class ItemTypeBuilder {\n        private Class\u003c?\u003e objectClass;\n        private Class\u003c?\u003e genericClass;\n\n        ItemTypeBuilder() {\n        }\n\n        public ItemTypeBuilder objectClass(final Class\u003c?\u003e objectClass) {\n            this.objectClass = objectClass;\n            return this;\n        }\n\n        public ItemTypeBuilder genericClass(final Class\u003c?\u003e genericClass) {\n            this.genericClass = genericClass;\n            return this;\n        }\n\n        public ItemType build() {\n            return new ItemType(this.objectClass, this.genericClass);\n        }\n    }\n}\n```\n\n### Custom Builder pattern:\n\nTo enable the transformation of Java Beans using the following Builder pattern:\n\n```java\npublic class ItemType {\n    private final Class\u003c?\u003e objectClass;\n    private final Class\u003c?\u003e genericClass;\n\n    ItemType(final ItemTypeBuilder builder) {\n        this.objectClass = builder.objectClass;\n        this.genericClass = builder.genericClass;\n    }\n\n    public static ItemTypeBuilder builder() {\n        return new ItemType.ItemTypeBuilder();\n    }\n\n    // getter methods\n\n    public static class ItemTypeBuilder {\n        private Class\u003c?\u003e objectClass;\n        private Class\u003c?\u003e genericClass;\n\n        ItemTypeBuilder() {\n        }\n\n        public ItemTypeBuilder objectClass(final Class\u003c?\u003e objectClass) {\n            this.objectClass = objectClass;\n            return this;\n        }\n\n        public ItemTypeBuilder genericClass(final Class\u003c?\u003e genericClass) {\n            this.genericClass = genericClass;\n            return this;\n        }\n\n        public ItemType build() {\n            return new ItemType(this);\n        }\n    }\n}\n```\n\nIt's needed to enable the custom Builder Transformation as follows:\n\n```java\nToBean toBean = new BeanTransformer()\n                         .setCustomBuilderTransformationEnabled(true)\n                         .transform(sourceObject, ToBean.class);\n```\n\n## Transform Java Record\n\n### Simple case:\n\n```java\npublic record FromFooRecord(BigInteger id, String name) {    public record RecordToFoo(BigInteger id, String name) {                           \n}                                                            }  \n```\nAnd one line code as:\n\n```java\nvar toBean = beanUtils.getTransformer().transform(fromBean, RecordToFoo.class);\n```\n\n## Constraints:\n\n* the class's fields that have to be copied must not be static\n\nMore sample beans can be found in the test package: `com.expediagroup.beans.sample`\n\n## Third-party library comparison\n\nFollowing a comparison between the BULL functionalities and the following Third-Party libraries:\n\n* [Apache BeanUtils](http://commons.apache.org/proper/commons-beanutils/)\n* [Jackson Data Bind](https://github.com/FasterXML/jackson-databind)\n* [Dozer](http://dozer.sourceforge.net/)\n\n|                                                                                                                         | **BULL** | **Apache Bean Utils** | **Jackson** | **Dozer** |\n|:------------------------------------------------------------------------------------------------------------------------|:--------:|:---------------------:|:-----------:|:---------:|\n| Mutable bean copy                                                                                                       |    X     |           X           |      X      |    X+     |\n| Mutable bean with nested objects                                                                                        |    X     |           -           |      X      |    X+     |\n| Mutable bean extending classes                                                                                          |    X     |           -           |      X      |    X+     |\n| Immutable bean copy                                                                                                     |    X     |           -           |      -      |    X*     |\n| Mixed bean copy                                                                                                         |    X     |           -           |      -      |    X+     |\n| Copy of beans without getter and setter methods defined                                                                 |    X     |           -           |      -      |     -     |\n| Mutable Bean with different field's name                                                                                |    X     |           -           |      -      |    X+     |\n| Mixed with different field's type                                                                                       |    X     |           -           |      -      |    X+     |\n| Immutable with different field's type                                                                                   |    X     |           -           |      -      |    X+     |\n| Mutable Bean containing collection type fields containing complex objects                                               |    X     |           -           |      X      |     X     |\n| Mixed Bean containing collection type fields containing complex objects                                                 |    X     |           -           |      -      |    X+     |\n| Immutable Bean containing collection type fields containing complex objects                                             |    X     |           -           |      -      |    X+     |\n| Mutable Bean containing containing Map type fields with nested Maps inside.  e.g. `Map\u003cString, Map\u003cString, Integer\u003e\u003e`   |    X     |           -           |      X      |     X     |\n| Mixed Bean containing containing Map type fields with nested Maps inside.  e.g. `Map\u003cString, Map\u003cString, Integer\u003e\u003e`     |    X     |           -           |      -      |    X+     |\n| Immutable Bean containing containing Map type fields with nested Maps inside.  e.g. `Map\u003cString, Map\u003cString, Integer\u003e\u003e` |    X     |           -           |      -      |    X+     |\n| Annotation field validation                                                                                             |    X     |           -           |      X      |     -     |\n\n_[*] Immutable types are not supported by Dozer. When a type doesn't have a no-arg constructor and all fields are final, Dozer can't perform the mapping.\nA workaround is introducing the Builder Pattern. An example can be found [here](http://codeslut.blogspot.com/2010/05/mapping-immutable-value-objects-with.html)_\n_[+] Requires a custom configuration_\n\n## Performance\n\nLet's have a look at the performance library performance. The test has been executed on the following objects:\n\n* Mutable objects\n* Mutable objects extending another mutable object\n* Immutable objects\n* Immutable objects extending another immutable object\n* Mixed objects\n\n|                                                                                               |                                      **Mutable**                                       |                                      **Immutable**                                       |                                      **Mixed**                                       |\n|:----------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------:|:----------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------:|\n| Simple objects (without nested objects)                                                       |                                        ~0.011ms                                        |                                         ~0.018ms                                         |                                          NA                                          |\n| Complex objects (containing several nested object and several items in Map and Array objects) |                                        ~0.37ms                                         |                                         ~0.21ms                                          |                                       ~0.22ms                                        | \n| CPU/Heap usage                                                                                | [~0.2%/35 MB](docs/site/resources/images/stats/performance/mutableObject/jvmStats.jpg) | [~0.2%/30 MB](docs/site/resources/images/stats/performance/immutableObject/jvmStats.jpg) | [~0.2%/25 MB](docs/site/resources/images/stats/performance/mixedObject/jvmStats.jpg) |\n\nTransformation time [screenshot](docs/site/resources/images/stats/performance/transformationTime.png)\n\n#### Real case testing\n\nThe Bean Utils library has been tested on a real case scenario integrating it into a real edge service (called BPE).\nThe purpose was to compare the latency introduced by the library plus the memory/CPU usage.\nThe dashboard's screenshot shows the latency of the invoked downstream service (called BPAS) and the one where the library has been installed (BPE).\nFollowing the obtained results:\n\n| | **Classic transformer** | **BeanUtils library** |\n| :----------- | :-----------: | :-----------: |\n| Throughput per second | 60 | 60 |\n| Average CPU usage | 0.3% | 0.3% |\n| Min/Max Heap Memory Usage (MB) | 90/320 | 90/320 |\n| Average Latency than the downstream service | +2ms | +2ms |\n| JVM stats screenshot | [screenshot](docs/site/resources/images/stats/performance/realTestCase/classicTransformer/jvmStats.jpg) | [screenshot](docs/site/resources/images/stats/performance/realTestCase/beanUtilsLib/jvmStats.jpg) |\n| Dashboard screenshot | [screenshot](docs/site/resources/images/stats/performance/realTestCase/classicTransformer/dashboard.jpg) | [screenshot](docs/site/resources/images/stats/performance/realTestCase/beanUtilsLib/dashboard.jpg) |\n\n## Validation samples\n\nValidating a java bean has never been so simple. The library offers different APIs related to this, following some examples:\n\n### Validate a Java Bean:\n\nGiven the following bean:\n\n```java\npublic class SampleBean {                           \n   @NotNull                   \n   private BigInteger id;                      \n   private String name;                 \n   \n   // constructor\n   // getters and setters... \n}                                                               \n```\n\nan instance of the above object:\n\n```java\nSampleBean sampleBean = new SampleBean();\n```\n\nAnd one line code as:\n\n```java\nbeanUtils.getValidator().validate(sampleBean);\n```\n\nthis will throw an `InvalidBeanException` as the `id` field is null.\n\n### Retrieve the violated constraints:\n\nGiven the following bean:\n\n```java\npublic class SampleBean {                           \n   @NotNull                   \n   private BigInteger id;                      \n   private String name;                 \n   \n   // constructor\n   // getters and setters... \n}                                                               \n```\n\nan instance of the above object:\n\n```java\nSampleBean sampleBean = new SampleBean();\n```\n\nAnd one line code as:\n\n```java\nList\u003cString\u003e violatedConstraints = beanUtils.getValidator().getConstraintViolationsMessages(sampleBean);\n```\n\nthis will return a list containing a constraint validation message for the `id` field as it's null and the constraint: `@NotNull` is not met.\n\nin case it's needed to have the `ConstraintViolation` object:\n```java\nSet\u003cConstraintViolation\u003cObject\u003e\u003e violatedConstraints = beanUtils.getValidator().getConstraintViolations(sampleBean);\n```\n\n## Primitive type object converter\n\nConverts a given primitive value into the given primitive type.\nThe supported types, in which an object can be converted (from/to), are:\n\n* `Byte`, `byte` or `byte[]`\n* `Short` or `short`\n* `Integer` or `int`\n* `Long` or `long`\n* `Float` or `float`\n* `Double` or `double`\n* `BigDecimal`\n* `BigInteger`\n* `Character` or `char`\n* `Boolean` or `boolean`\n* `String`\n\n### Convert a String into an int:\n\nGiven the following variable:\n\n```java\nString indexNumber = \"26062019\";                                                        \n```\n\nto convert it in an `int`:\n\n```java\nConverter converter = new BeanUtils().getPrimitiveTypeConverter();\nint indexNumber = converter.convertValue(indexNumber, int.class);\n```\n\n### Obtain a conversion function that converts from char to byte:\n\nIt's possible to obtain a type conversion function, reusable several times in different places.\nAssuming that the required conversion is from `char` to `byte\n\n```java\nchar c = '1';                                                        \n```\n\nthe conversion function is retrieved through:\n\n```java\nConverter converter = new BeanUtils().getPrimitiveTypeConverter();\nOptional\u003cFunction\u003cObject, Object\u003e\u003e conversionFunction = converter.getConversionFunction(char.class, byte.class);\nbyte converted = conversionFunction.map(processor -\u003e processor.apply(c)).orElse(0);\n```\n\n* in case the conversion is not needed as the primitive type and the destination type are the same it will return an empty `Optional`\n* in case the conversion function is unavailable or no not possible the method throws a: `TypeConversionException`\n\n## `Map` transformation samples\n\nSamples on how to transform a `Map` and all others function applicable to it can be viewed [here](https://opensource.expediagroup.com/bull/transformer/mapTransformer.html)\n\n## Documentation\n\nDetailed project documentation is available [here](https://opensource.expediagroup.com/bull), including some samples for [testing the library](https://opensource.expediagroup.com/bull/transformer/testing.html) inside your project.\n\nAn article that explains how it works, with suggestions and examples, is available on DZone: [How to Transform Any Type of Java Bean With BULL](https://dzone.com/articles/how-to-transform-any-type-of-java-bean-with-one-li)\n\n## Credits\n\nCreated by: [Fabio Borriello](https://github.com/fborriello) with the contribution of: [Patrizio Munzi](https://github.com/patriziomunzi),\n[Andrea Marsiglia](https://github.com/AndreaMars94), [Giorgio Delle Grottaglie](https://github.com/giorgiodg/) \u0026 the Hotels.com's Checkout team in Rome.\n\nThe application's logo has been designed by Rob Light.\n\n## Related articles\n\n- DZone: [How to Transform Any Type of Java Bean With BULL](https://dzone.com/articles/how-to-transform-any-type-of-java-bean-with-one-li)\n- InfoQ: [How Expedia Is Getting Rid of Java Bean Transformers](https://www.infoq.com/articles/expedia-rid-of-bean-transformers/) [[EN](https://www.infoq.com/articles/expedia-rid-of-bean-transformers/)] [[PT-BR](https://www.infoq.com/br/articles/expedia-rid-of-bean-transformers/)]\n\n## Release\n\nAll the instructions for releasing a new version are available at [RELEASES.md](RELEASE.md)\n\n## Badge your project\n\n[![Bull enabled](https://img.shields.io/badge/bull-enabled-red?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAA8FBMVEUAAADRKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi////+bJRrYAAAATnRSTlMAABoFB0UGATtcHQsinVIEAz3Dy6QwHmzlylsTl/uGVvXonjMm0+pLApjjNO3nv0H3/N9VTVnauEn49r391vCCcnsJCn76aa6LFxnVZrus5DL8AAAApElEQVR42k2NA7rDABAGM89mbZupbbd7/9sU8Xzc/aUYwN09igMeHp+eHR94eX17tx/w8fn1+m08gJ/fv3+XG+vh8fpE/AEPGI9gKCxXIrYlGhOJJ5KWI5UWyWRzmBP3+au/UASe0Qy/peujXKlyr9XyHJIrtbraaLa0x1tbdGKdlPbo9vqDQX84GstEu5kOZ/PFcrXOqpsf7bFN72B/mHA8LVAuoY0XA5ziPJYAAAAASUVORK5CYII=)](https://github.com/ExpediaGroup/bull)\n\nAdd the following snippet in your Markdown file:\n\n```\n[![Bull enabled](https://img.shields.io/badge/bull-enabled-red?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAA8FBMVEUAAADRKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi/RKi////+bJRrYAAAATnRSTlMAABoFB0UGATtcHQsinVIEAz3Dy6QwHmzlylsTl/uGVvXonjMm0+pLApjjNO3nv0H3/N9VTVnauEn49r391vCCcnsJCn76aa6LFxnVZrus5DL8AAAApElEQVR42k2NA7rDABAGM89mbZupbbd7/9sU8Xzc/aUYwN09igMeHp+eHR94eX17tx/w8fn1+m08gJ/fv3+XG+vh8fpE/AEPGI9gKCxXIrYlGhOJJ5KWI5UWyWRzmBP3+au/UASe0Qy/peujXKlyr9XyHJIrtbraaLa0x1tbdGKdlPbo9vqDQX84GstEu5kOZ/PFcrXOqpsf7bFN72B/mHA8LVAuoY0XA5ziPJYAAAAASUVORK5CYII=)](https://github.com/ExpediaGroup/bull)\n```\n\n## Support\n\n[![Join the chat at https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk](https://img.shields.io/badge/chat-on%20slack-ff69b4.svg)](https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk)\n\nFor any question, proposal, or help, please refer to the slack channel: [#bull](https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk).\n\n## Legal\n\nThis project is available under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0.html).\n\nCopyright 2018-2023 Expedia Inc.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpediagroup%2Fbull","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexpediagroup%2Fbull","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexpediagroup%2Fbull/lists"}