• Stars
    star
    185
  • Rank 208,271 (Top 5 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created almost 6 years ago
  • Updated about 2 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

BULL - Bean Utils Light Library

BULL

Bean Utils Light Library

BULL 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. It's the only library able to transform Mutable, Immutable, and Mixed bean without any custom configuration.

Start using

Maven Central Javadocs Build Status Join the chat at https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk

GitHub site Coverage Status Security Rating License Dependabot

All BULL modules are available on Maven Central:

  • Bean BOM

It contains all the modules available in the project

<dependency>
    <groupId>com.expediagroup.beans</groupId>
    <artifactId>bull-bom</artifactId>
    <version>x.y.z</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>
  • Bean Transformer

<dependency>
    <groupId>com.expediagroup.beans</groupId>
    <artifactId>bull-bean-transformer</artifactId>
    <version>x.y.z</version>
</dependency>
  • Map Transformer

<dependency>
    <groupId>com.expediagroup.beans</groupId>
    <artifactId>bull-map-transformer</artifactId>
    <version>x.y.z</version>
</dependency>

The project provides two different builds, one compatible with jdk 8 (or above), one with jdk 11 and on with jdk 15 or above.

In case you need to integrate it in a:

Some jdk versions remove the Java Bean constructor's argument names from the compiled code and this may cause problems to the library. On top of that, it's suggested to configure the maven-compiler-plugin, inside your project, as follow:

<build>
    ...
    <pluginManagement>
        <plugins>
            ...
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven.compiler.plugin.version}</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                    <parameters>true</parameters>
                    <forceJavacCompilerUse>true</forceJavacCompilerUse>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>
    ...
</build>

Maven build

Full build

./mvnw clean install

or on Windows

mvnw.cmd clean install

Skip test coverage and checkstyle check

./mvnw clean install -P relaxed

or on Windows

mvnw.cmd clean install -P relaxed

Check for dependencies update

mvn versions:display-dependency-updates -P check-for-updates

or on Windows

mvnw.cmd versions:display-dependency-updates -P check-for-updates

Features:

  • support copy of immutable beans.
  • support copy of mutable beans.
  • support copy of hybrid beans (some fields private and some not).
  • support copy of Java Records.
  • support copy of Java beans without getter and setter methods.
  • support copy with Java primitive type.
  • support copy with Java Collection type. e.g. List<BeanA> => List<BeanB>
  • support copy with nested map fields. e.g. Map<String, Map<String, String>>
  • support copy with array containing primitive types. e.g. String[] => String[]
  • support copy with an array type. e.g. BeanA[] => BeanB[]
  • support copy with property name mapping. e.g. int id => int userId
  • support copy with recursion copy.
  • support validation through annotations.
  • support copy of beans with different field's name.
  • support lambda function field transformation.
  • support copy of java bean built through Builder.
  • easy usage, declarative way to define the property mapping (in case of different names), or simply adding the Lombok annotations.
  • allows setting the default value for all objects not existing in the source object.
  • allows skipping transformation for a given set of fields.
  • supports the retrieval of the value from getters if a field does not exist in the source object.
  • supports the automatic conversion of primitive types.

Feature samples

Bean transformation samples

Simple case:

public class FromBean {                                     public class ToBean {
    private final String name;                                  @NotNull
    private final BigInteger id;                                public BigInteger id;
    private final List<FromSubBean> subBeanList;                private final String name;
    private List<String> list;                                  private final List<String> list;
    private final FromSubBean subObject;                        private final List<ToSubBean> subBeanList;
    private ImmutableToSubFoo subObject;

    // all constructors                                         // all args constructor
    // getters and setters...                                   // getters and setters... 
}    

And one line code as:

ToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);

Different field names copy:

From class and To class with different field names:

public class FromBean {                                     public class ToBean {

    private final String name;                                  private final String differentName;
    private final int id;                                       private final int id;
    private final List<FromSubBean> subBeanList;                private final List<ToSubBean> subBeanList;
    private final List<String> list;                            private final List<String> list;
    private final FromSubBean subObject;                        private final ToSubBean subObject;

    // getters...
    public ToBean(final String differentName,
                  final int id,
}                                                                       final List<ToSubBean> subBeanList,
    final List<String> list,
    final ToSubBean subObject) {
        this.differentName = differentName;
        this.id = id;
        this.subBeanList = subBeanList;
        this.list = list;
        this.subObject = subObject;
    }

    // getters...           

}

And one line code as:

beanUtils.getTransformer().withFieldMapping(new FieldMapping<>("name", "differentName")).transform(fromBean, ToBean.class);                                                               

it is also possible to map a field in the source class into multiple fields in the destination object.

Given the following source class:

public class SourceClass {
    private final String name;
    private final int id;
}

the following destination class:

public class DestinationClass {
    private final String name;
    private final int id;
    private final int index;
}

and the following operations:

var sourceObj = new SourceClass("foo", 123);

var multipleFieldMapping = new FieldMapping<>("id", "index", "identifier");

var destObj = new BeanUtils().getBeanTransformer()
                     .withFieldMapping(multipleFieldMapping)
                     .transform(sourceObj, DestinationClass.class);

System.out.println("name = " + destObj.getName());
System.out.println("id = " + destObj.getId());
System.out.println("index = " + destObj.getIndex());

the output will be:

name = foo
id = 123
index = 123

Mapping destination fields with correspondent fields contained inside one of the nested objects in the source object:

Assuming that the object FromSubBean is declared as follow:

public class FromSubBean {

    private String serialNumber;
    private Date creationDate;

    // getters and setters... 

}

and our source object and destination object are described as follow:

public class FromBean {                                     public class ToBean {

    private final int id;                                       private final int id;
    private final String name;                                  private final String name;
    private final FromSubBean subObject;                        private final String serialNumber;
    private final Date creationDate;

    // all args constructor                                     // all args constructor
    // getters...                                               // getters... 

}                                                           }

the fields: serialNumber and creationDate needs to be retrieved from subObject, this can be done by defining the whole path to the end property:

FieldMapping serialNumberMapping = new FieldMapping<>("subObject.serialNumber", "serialNumber");                                                             
FieldMapping creationDateMapping = new FieldMapping<>("subObject.creationDate", "creationDate");
                                                             
beanUtils.getTransformer()
         .withFieldMapping(serialNumberMapping, creationDateMapping)
         .transform(fromBean, ToBean.class);                                                               

Different field names defining constructor args:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private final String differentName;                   
   private final int id;                                       private final int id;                      
   private final List<FromSubBean> subBeanList;                private final List<ToSubBean> subBeanList;                 
   private final List<String> list;                            private final List<String> list;                    
   private final FromSubBean subObject;                        private final ToSubBean subObject;                    
   
   // all args constructor
   // getters...
                                                               public ToBean(@ConstructorArg("name") final String differentName, 
                                                                        @ConstructorArg("id") final int id,
}                                                                       @ConstructorArg("subBeanList") final List<ToSubBean> subBeanList,
                                                                        @ConstructorArg(fieldName ="list") final List<String> list,
                                                                        @ConstructorArg("subObject") final ToSubBean subObject) {
                                                                        this.differentName = differentName;
                                                                        this.id = id;
                                                                        this.subBeanList = subBeanList;
                                                                        this.list = list;
                                                                        this.subObject = subObject; 
                                                                    }
                                                                
                                                                    // getters...           
                                              
                                                            }

And one line code as:

ToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);

Different field names and types applying transformation through lambda function:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  @NotNull                   
   private final BigInteger id;                                public BigInteger identifier;                      
   private final BigInteger index;                             public BigInteger index;                      
   private final List<FromSubBean> subBeanList;                private final String name;                 
   private List<String> list;                                  private final List<String> list;                    
   private final FromSubBean subObject;                        private final List<ImmutableToSubFoo> nestedObjectList;                    
   private final String locale;                                private final Locale locale;                    
                                                               private ImmutableToSubFoo nestedObject;
       
   // constructors...                                          // constructors...
   // getters and setters...                                   // getters and setters...
                                                                                                                              
}                                                           }
FieldTransformer<BigInteger, BigInteger> fieldTransformer = new FieldTransformer<>("identifier", BigInteger::negate);
FieldTransformer<String, Locale> localeTransformer = new FieldTransformer<>("locale", Locale::forLanguageTag);
beanUtils.getTransformer()
    .withFieldMapping(new FieldMapping<>("id", "identifier"))
    .withFieldTransformer(fieldTransformer).transform(fromBean, ToBean.class)
    .withFieldTransformer(localeTransformer);

It's also possible to apply the same transformation function on multiple fields. Taking as an example the above bean and assuming that we would negate both the id and the identifier, the transformer function has to be defined as follows:

FieldTransformer<BigInteger, BigInteger> fieldTransformer = new FieldTransformer<>(List.of("identifier", "index"), BigInteger::negate);

Assign a default value in case of missing field in the source object:

Assign a default value in case of a missing field in the source object:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  @NotNull                   
   private final BigInteger id;                                public BigInteger id;                      
                                                               private final String name;                 
                                                               private String notExistingField; // this will be null and no exceptions will be raised

   // constructors...                                          // constructors...
   // getters...                                               // getters and setters...

}                                                           }

And one line code as:

ToBean toBean = beanUtils.getTransformer()
                    .setDefaultValueForMissingField(true).transform(fromBean, ToBean.class);

Disable the default value set for primitive types in case they are null:

BULL by default sets the default value for all primitive types fields in case their value is in the source object. Given the following Java Bean:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  @NotNull                   
   private final BigInteger id;                                public BigInteger id;                      
                                                               private final String name;                 

   // constructors...                                          // constructors...
   // getters...                                               // getters and setters...

}                                                           }

in case the field id in the FromBean object is null, the value assigned the correspondent field in the ToBean object will be 0. To disable this you can simply do:

ToBean toBean = beanUtils.getTransformer()
                    .setDefaultValueForMissingPrimitiveField(false).transform(fromBean, ToBean.class);

in this case, the field id after the transformation will be null

Applying a transformation function in case of missing fields in the source object:

Assign a default value in case of a missing field in the source object:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  @NotNull                   
   private final BigInteger id;                                public BigInteger id;                      
                                                               private final String name;                 
                                                               private String notExistingField; // this will have value: sampleVal
                                                               
   // all args constructor                                     // constructors...
   // getters...                                               // getters and setters...
}                                                           }

And one line code as:

FieldTransformer<String, String> notExistingFieldTransformer = new FieldTransformer<>("notExistingField", () -> "sampleVal");
ToBean toBean = beanUtils.getTransformer()
                    .withFieldTransformer(notExistingFieldTransformer)
                    .transform(fromBean, ToBean.class);

Apply a transformation function on a field contained in a nested object:

This example shows how a lambda transformation function can be applied to a nested object field.

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private final String name;                   
   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    

   // all args constructor                                     // all args constructor
   // getters...                                               // getters...
}                                                           }

and

public class ToSubBean {                           
   private final String name;                   
   private final long index;                    
}

Assuming 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 follow:

FieldTransformer<String, String> nameTransformer = new FieldTransformer<>("nestedObject.name", StringUtils::capitalize);
ToBean toBean = beanUtils.getTransformer()
                    .withFieldTransformer(nameTransformer)
                    .transform(fromBean, ToBean.class);

Map a primitive type field in the source object into a nested object:

This example shows how to map a primitive field into a nested object into the destination one.

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private final String name;                   
   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    
   private final int x;
   // all args constructor                                     // all args constructor
   // getters...                                               // getters...
}                                                           }

and

public class ToSubBean {                           
   private final int x;
   
   // all args constructor
}  // getters...          

Assuming that the value x should be mapped into the field: x contained into the ToSubBean object, the field mapping has to be defined as follow:

ToBean toBean = beanUtils.getTransformer()
                    .withFieldMapping(new FieldMapping<>("x", "nestedObject.x"));

Apply a transformation function on all fields matching with the given one:

This example shows how a lambda transformation function can be applied to all fields matching with the given one independently from their position.

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private final String name;                   
   private final FromSubBean nestedObject;                     private final ToSubBean nestedObject;                    

   // all args constructor                                     // all args constructor
   // getters...                                               // getters...
}                                                           }

and

public class FromSubBean {                                  public class ToSubBean {                           
   private final String name;                                  private final String name;                   
   private final long index;                                   private final long index;                    
   
   // all args constructor                                     // all args constructor
   // getters...                                               // getters...
}                                                           }

Assuming 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 as follow:

FieldTransformer<String, String> nameTransformer = new FieldTransformer<>("name", StringUtils::capitalize);
ToBean toBean = beanUtils.getTransformer()
                    .setFlatFieldNameTransformation(true)
                    .withFieldTransformer(nameTransformer)
                    .transform(fromBean, ToBean.class);

Static transformer function:

List<FromFooSimple> fromFooSimpleList = Arrays.asList(fromFooSimple, fromFooSimple);

can be transformed as follow:

Function<FromFooSimple, ImmutableToFooSimple> transformerFunction = BeanUtils.getTransformer(ImmutableToFooSimple.class);
List<ImmutableToFooSimple> actual = fromFooSimpleList.stream()
                .map(transformerFunction)
                .collect(Collectors.toList());

or if you have a pre-configured transformer:

Function<FromFooSimple, ImmutableToFooSimple> transformerFunction = BeanUtils.getTransformer(<yourPreconfiguredTransformer>, ImmutableToFooSimple.class);
List<ImmutableToFooSimple> actual = fromFooSimpleList.stream()
                .map(transformerFunction)
                .collect(Collectors.toList());

Enable Java Beans validation:

Assuming that the field: id in the fromBean instance is null.

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  @NotNull                   
   private final BigInteger id;                                public BigInteger id;                      
                                                               private final String name;

   // all args constructor                                     // all args constructor
   // getters...                                               // getters and setters...
}                                                            }

adding the following configuration an exception will be thrown:

ToBean toBean = beanUtils.getTransformer()
                     .setValidationEnabled(true)
                     .transform(fromBean, ToBean.class);

Copy on an existing instance:

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private String name;                   
   private final FromSubBean nestedObject;                     private ToSubBean nestedObject;                    

   // all args constructor                                     // constructor
   // getters...                                               // getters and setters...
}                                                           }

if you need to perform the copy on an already existing object, just do:

ToBean toBean = new ToBean();
beanUtils.getTransformer().transform(fromBean, toBean);

Skip transformation on a given set of fields:

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private String name;                   
   private final FromSubBean nestedObject;                     private ToSubBean nestedObject;                    

   // all args constructor                                     // constructor
   // getters...                                               // getters and setters...
}                                                           }

public class FromBean2 {                   
   private final int index;             
   private final FromSubBean nestedObject;
                                          
   // all args constructor                
   // getters...                          
}                                         

if you need to skip the transformation for a given field, just do:

ToBean toBean = new ToBean();
beanUtils.getTransformer()
    .skipTransformationForField("nestedObject")
    .transform(fromBean, toBean);

where nestedObject is the name of the field in the destination object.

This feature allows us to transform an object keeping the data from different sources.

To better explain this function let's assume that the ToBean (defined above) should be transformed as follow:

  • name field value has been taken from the FromBean object
  • nestedObject field value has been taken from the FromBean2 object

the objective can be reached by doing:

// create the destination object
ToBean toBean = new ToBean();

// execute the first transformation skipping the copy of: 'nestedObject' field that should come from the other source object
beanUtils.getTransformer()
    .skipTransformationForField("nestedObject")
    .transform(fromBean, toBean);

// then execute the transformation skipping the copy of: 'name' field that should come from the other source object
beanUtils.getTransformer()
    .skipTransformationForField("name")
    .transform(fromBean2, toBean);

Keep a field type value from the source object as is:

Given:

public class FromBean {                                     public class ToBean {                           
   private final String name;                                  private String name;                   
   private final DateTime dateTime;                            private final DateTime dateTime;              

   // all args constructor                                     // constructor
   // getters...                                               // getters and setters...
}                                                           }

if 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 by doing:

ClassUtils.CUSTOM_SPECIAL_TYPES.add(DateTime.class);

ToBean toBean = new ToBean();
beanUtils.getTransformer()
    .transform(fromBean, toBean);

Not existing field in the source object:

In 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.

public class FromBean {                                     public class ToBean {                           
                                                               private final BigInteger id;
    public BigInteger getId() {                                   
        return BigInteger.TEN;                                 // all args constructor
   }                                                           // getters...
}                                                               
                                                            }

And one line code as:

ToBean toBean = beanUtils.getTransformer().transform(fromBean, ToBean.class);

Transform primitive types automatically

Given the following Java Bean:

public class FromBean {                                     public class ToBean {                           
   private final String indexNumber;                           private final int indexNumber;                                 
   private final BigInteger id;                                public Long id;                      

   // constructors...                                          // constructors...
   // getters...                                               // getters and setters...

}                                                           }

as, by default the primitive type conversion is disabled, to get the above object converted we should have implemented transformer functions for both field indexNumber and id, but this can be done automatically by enabling the the functionality described above.

Transformer transformer = beanUtils.getTransformer()
                             .setPrimitiveTypeConversionEnabled(true);

ToBean toBean = transformer.transform(fromBean, ToBean.class);

IMPORTANT: The primitive type transformation (if enabled) is executed before any other FieldTransformer function is defined on a specific field. This means that once the FieldTransformer function will be executed the field value has already been transformed.

Builder supported patterns

The library supports the transformation of Java Bean using the following Builder patterns:

Standard pattern:

public class ItemType {
    private final Class<?> objectClass;
    private final Class<?> genericClass;

    ItemType(final Class<?> objectClass, final Class<?> genericClass) {
        this.objectClass = objectClass;
        this.genericClass = genericClass;
    }

    public static ItemTypeBuilder builder() {
        return new ItemType.ItemTypeBuilder();
    }

    // getter methods

    public static class ItemTypeBuilder {
        private Class<?> objectClass;
        private Class<?> genericClass;

        ItemTypeBuilder() {
        }

        public ItemTypeBuilder objectClass(final Class<?> objectClass) {
            this.objectClass = objectClass;
            return this;
        }

        public ItemTypeBuilder genericClass(final Class<?> genericClass) {
            this.genericClass = genericClass;
            return this;
        }

        public ItemType build() {
            return new ItemType(this.objectClass, this.genericClass);
        }
    }
}

Custom Builder pattern:

To enable the transformation of Java Beans using the following Builder pattern:

public class ItemType {
    private final Class<?> objectClass;
    private final Class<?> genericClass;

    ItemType(final ItemTypeBuilder builder) {
        this.objectClass = builder.objectClass;
        this.genericClass = builder.genericClass;
    }

    public static ItemTypeBuilder builder() {
        return new ItemType.ItemTypeBuilder();
    }

    // getter methods

    public static class ItemTypeBuilder {
        private Class<?> objectClass;
        private Class<?> genericClass;

        ItemTypeBuilder() {
        }

        public ItemTypeBuilder objectClass(final Class<?> objectClass) {
            this.objectClass = objectClass;
            return this;
        }

        public ItemTypeBuilder genericClass(final Class<?> genericClass) {
            this.genericClass = genericClass;
            return this;
        }

        public ItemType build() {
            return new ItemType(this);
        }
    }
}

It's needed to enable the custom Builder Transformation as follows:

ToBean toBean = new BeanTransformer()
                         .setCustomBuilderTransformationEnabled(true)
                         .transform(sourceObject, ToBean.class);

Transform Java Record

Simple case:

public record FromFooRecord(BigInteger id, String name) {    public record RecordToFoo(BigInteger id, String name) {                           
}                                                            }  

And one line code as:

var toBean = beanUtils.getTransformer().transform(fromBean, RecordToFoo.class);

Constraints:

  • the class's fields that have to be copied must not be static

More sample beans can be found in the test package: com.expediagroup.beans.sample

Third-party library comparison

Following a comparison between the BULL functionalities and the following Third-Party libraries:

BULL Apache Bean Utils Jackson Dozer
Mutable bean copy X X X X+
Mutable bean with nested objects X - X X+
Mutable bean extending classes X - X X+
Immutable bean copy X - - X*
Mixed bean copy X - - X+
Copy of beans without getter and setter methods defined X - - -
Mutable Bean with different field's name X - - X+
Mixed with different field's type X - - X+
Immutable with different field's type X - - X+
Mutable Bean containing collection type fields containing complex objects X - X X
Mixed Bean containing collection type fields containing complex objects X - - X+
Immutable Bean containing collection type fields containing complex objects X - - X+
Mutable Bean containing containing Map type fields with nested Maps inside. e.g. Map<String, Map<String, Integer>> X - X X
Mixed Bean containing containing Map type fields with nested Maps inside. e.g. Map<String, Map<String, Integer>> X - - X+
Immutable Bean containing containing Map type fields with nested Maps inside. e.g. Map<String, Map<String, Integer>> X - - X+
Annotation field validation X - X -

[*] 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. A workaround is introducing the Builder Pattern. An example can be found here [+] Requires a custom configuration

Performance

Let's have a look at the performance library performance. The test has been executed on the following objects:

  • Mutable objects
  • Mutable objects extending another mutable object
  • Immutable objects
  • Immutable objects extending another immutable object
  • Mixed objects
Mutable Immutable Mixed
Simple objects (without nested objects) ~0.011ms ~0.018ms NA
Complex objects (containing several nested object and several items in Map and Array objects) ~0.37ms ~0.21ms ~0.22ms
CPU/Heap usage ~0.2%/35 MB ~0.2%/30 MB ~0.2%/25 MB

Transformation time screenshot

Real case testing

The Bean Utils library has been tested on a real case scenario integrating it into a real edge service (called BPE). The purpose was to compare the latency introduced by the library plus the memory/CPU usage. The dashboard's screenshot shows the latency of the invoked downstream service (called BPAS) and the one where the library has been installed (BPE). Following the obtained results:

Classic transformer BeanUtils library
Throughput per second 60 60
Average CPU usage 0.3% 0.3%
Min/Max Heap Memory Usage (MB) 90/320 90/320
Average Latency than the downstream service +2ms +2ms
JVM stats screenshot screenshot screenshot
Dashboard screenshot screenshot screenshot

Validation samples

Validating a java bean has never been so simple. The library offers different APIs related to this, following some examples:

Validate a Java Bean:

Given the following bean:

public class SampleBean {                           
   @NotNull                   
   private BigInteger id;                      
   private String name;                 
   
   // constructor
   // getters and setters... 
}                                                               

an instance of the above object:

SampleBean sampleBean = new SampleBean();

And one line code as:

beanUtils.getValidator().validate(sampleBean);

this will throw an InvalidBeanException as the id field is null.

Retrieve the violated constraints:

Given the following bean:

public class SampleBean {                           
   @NotNull                   
   private BigInteger id;                      
   private String name;                 
   
   // constructor
   // getters and setters... 
}                                                               

an instance of the above object:

SampleBean sampleBean = new SampleBean();

And one line code as:

List<String> violatedConstraints = beanUtils.getValidator().getConstraintViolationsMessages(sampleBean);

this will return a list containing a constraint validation message for the id field as it's null and the constraint: @NotNull is not met.

in case it's needed to have the ConstraintViolation object:

Set<ConstraintViolation<Object>> violatedConstraints = beanUtils.getValidator().getConstraintViolations(sampleBean);

Primitive type object converter

Converts a given primitive value into the given primitive type. The supported types, in which an object can be converted (from/to), are:

  • Byte, byte or byte[]
  • Short or short
  • Integer or int
  • Long or long
  • Float or float
  • Double or double
  • BigDecimal
  • BigInteger
  • Character or char
  • Boolean or boolean
  • String

Convert a String into an int:

Given the following variable:

String indexNumber = "26062019";                                                        

to convert it in an int:

Converter converter = new BeanUtils().getPrimitiveTypeConverter();
int indexNumber = converter.convertValue(indexNumber, int.class);

Obtain a conversion function that converts from char to byte:

It's possible to obtain a type conversion function, reusable several times in different places. Assuming that the required conversion is from char to `byte

char c = '1';                                                        

the conversion function is retrieved through:

Converter converter = new BeanUtils().getPrimitiveTypeConverter();
Optional<Function<Object, Object>> conversionFunction = converter.getConversionFunction(char.class, byte.class);
byte converted = conversionFunction.map(processor -> processor.apply(c)).orElse(0);
  • in case the conversion is not needed as the primitive type and the destination type are the same it will return an empty Optional
  • in case the conversion function is unavailable or no not possible the method throws a: TypeConversionException

Map transformation samples

Samples on how to transform a Map and all others function applicable to it can be viewed here

Documentation

Detailed project documentation is available here, including some samples for testing the library inside your project.

An article that explains how it works, with suggestions and examples, is available on DZone: How to Transform Any Type of Java Bean With BULL

Credits

Created by: Fabio Borriello with the contribution of: Patrizio Munzi, Andrea Marsiglia, Giorgio Delle Grottaglie & the Hotels.com's Checkout team in Rome.

The application's logo has been designed by Rob Light.

Related articles

Release

All the instructions for releasing a new version are available at RELEASES.md

Badge your project

Bull enabled

Add the following snippet in your Markdown file:

[![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)

Support

Join the chat at https://join.slack.com/t/bull-crew/shared_invite/enQtNjM1MTE5ODg1MTQzLWI5ODhhYTQ2OWQxODgwYzU1ODMxMWJiZDkzODM3OTJkZjBlM2MwMTI3ZWZjMmU0OGZmN2RmNjg4NWI2NTMzOTk

For any question, proposal, or help, please refer to the slack channel: #bull.

Legal

This project is available under the Apache 2.0 License.

Copyright 2018-2023 Expedia Inc.

More Repositories

1

graphql-kotlin

Libraries for running GraphQL in Kotlin
Kotlin
1,732
star
2

cyclotron

A web platform for constructing dashboards.
CoffeeScript
1,560
star
3

waggle-dance

Hive federation service. Enables disparate tables to be concurrently accessed across multiple Hive deployments.
Java
266
star
4

styx

Programmable, asynchronous, event-based reverse proxy for JVM.
Java
253
star
5

adaptive-alerting

Anomaly detection for streaming time series, featuring automated model selection.
Java
202
star
6

jenkins-spock

Unit-test Jenkins pipeline code with Spock
Groovy
187
star
7

c3vis

Visualize the resource utilisation of Amazon ECS clusters
JavaScript
165
star
8

jarviz

Jarviz is dependency analysis and visualization tool designed for Java applications
Java
133
star
9

stream-registry

Stream Discovery and Stream Orchestration
Java
122
star
10

flyte

Flyte binds together the tools you use into easily defined, automated workflows
Go
88
star
11

circus-train

Circus Train is a dataset replication tool that copies Hive tables between clusters and clouds.
Java
86
star
12

kubernetes-sidecar-injector

Kuberbetes mutating webhook that injects a sidecar container to a pod
Go
76
star
13

expediagroup.github.io

The Expedia Group Open Source portal, a website for discovering EG open source projects.
JavaScript
64
star
14

mittens

Warm-up routine for http applications over REST and gRPC
Go
64
star
15

avro-compatibility

A user friendly API for checking for and reporting on Avro schema incompatibilities.
Java
59
star
16

graphql-component

Composeable graphql components
JavaScript
55
star
17

heat

Heat Test Framework
Java
45
star
18

beekeeper

Service for automatically managing and cleaning up unreferenced data
Java
45
star
19

pitchfork

Convert tracing data between Zipkin and Haystack formats
Java
44
star
20

container-startup-autoscaler

A Kubernetes controller that modifies the CPU and/or memory resources of containers depending on whether they're starting up, according to the startup/post-startup settings you supply.
Go
37
star
21

apiary

Apiary provides modules which can be combined to create a federated cloud data lake
36
star
22

github-helpers

A collection of Github Actions that simplify and standardize common CI/CD workflow tasks.
TypeScript
35
star
23

pino-rotating-file

[DEPRECATED] A pino log transport for splitting logs into separate, automatically rotating files.
JavaScript
33
star
24

javro

JSON Schema to Avro Mapper
JavaScript
29
star
25

rhapsody

Reactive Streams framework with support for at-least-once processing
Java
29
star
26

vsync

Sync Secrets between HashiCorp vaults
Go
29
star
27

kube-graffiti

Paint your kubernetes objects with 'mutating' webhooks
Go
26
star
28

hiveberg

Demonstration of a Hive Input Format for Iceberg
Java
26
star
29

plunger

A unit testing framework for the Cascading data processing platform.
Java
25
star
30

beeju

JUnit integration for testing the Apache Hive Metastore and HiveServer2 Thrift APIs
Java
24
star
31

react-event-tracking

React shared context utilities for analytic event tracking.
JavaScript
23
star
32

expediagroup.github.io-old

Expedia Group OSS Portal
HTML
22
star
33

shunting-yard

Shunting Yard is a real-time data replication tool that copies data between Hive Metastores.
Java
20
star
34

jasvorno

A library for strong, schema based conversion between 'natural' JSON documents and Avro
Java
18
star
35

apiary-data-lake

Terraform scripts for deploying Apiary Data Lake
HCL
18
star
36

datasqueeze

Hadoop utility to compact small files
Java
18
star
37

hello-streams

hello-streams :: Introducing the stream-first mindset
Java
17
star
38

map-maker

Map maker is a command line tool and library for easily generating maps from structured data.
Jupyter Notebook
15
star
39

spinnaker-pipeline-trigger

Pipeline trigger for Spinnaker utilizing SNS
TypeScript
15
star
40

corc

An ORC File Scheme for the Cascading data processing platform.
Java
14
star
41

steerage

[DEPRECATED] Hapi server configuration and composition using confidence, topo, and shortstop.
JavaScript
14
star
42

fpsmeter

Optimized javascript utility for measuring frames per second in a browser environment. Useful for observing end-user client run-time performance without adversly impacting performance.
JavaScript
14
star
43

insights-explorer

Insights Explorer is a tool to catalogue and present analytical & research work.
TypeScript
13
star
44

molten

Molten is an opinionated library providing reactive tooling to simplify building production-ready integration solutions using Reactor.
Java
13
star
45

service-client

[DEPRECATED] A general purpose http client built with extensibility in mind. It also features lifecycle hooks, dynamic hostname resolution, and circuit breaking.
JavaScript
12
star
46

github-webhook-proxy

Request forwarder for GitHub webhooks from github.com to internal enterprise destinations, designed for use in Github Enterprise Cloud.
TypeScript
10
star
47

apiary-extensions

Extensions available for use in Apiary
Java
10
star
48

drone-fly

A service which allows Hive Metastore Listeners to be deployed outside of the Hive Metastore Service
Java
10
star
49

secrets-injector

Go
9
star
50

neaps

a simulator to forecast the end of agile project basing on historical data and using montecarlo simulations
JavaScript
9
star
51

cypress-codegen

A Cypress plugin which automatically adds and enables IntelliSense for your custom commands!
TypeScript
9
star
52

circus-train-bigquery

Circus Train plugin which replicates BigQuery tables to Hive
Java
8
star
53

quibble

Data validator tool to allows testers, developers and analysts to define and execute test-cases involving data. Quibble is able to compare data from one or more data platforms, assert on the outcome and produce generated report output on any anomalies in data.
Java
8
star
54

dr-shadow

Dr Shadow is a library developed by Egencia (part of Expedia Group) that enables shadow traffic (ie. mirroring). It is a valuable tool for having good hygiene for service operations (ie. testing, resiliency, performance).
Java
6
star
55

flyte-client

A Go library designed to make the writing of flyte packs simple
Go
6
star
56

catalyst-server

[DEPRECATED] Configuration and composition management for Hapi.js applications.
JavaScript
6
star
57

comparadise

A visual comparison tool for reviewing visual changes on frontend PRs.
TypeScript
6
star
58

hello-cloud

hello world example for Multicloud applications
HTML
6
star
59

two-tower-lodging-candidate-generation

Python
6
star
60

aws-adfs-login

Library for user login (client side) using AWS ADFS (Active Directory Federation Service)
Go
5
star
61

apiary-federation

Terraform scripts for deploying Apiary Data Lake federation
HCL
5
star
62

apiary-metastore-docker

Docker image for Apiary Data Lake metastore
Shell
5
star
63

apiary-ranger-docker

Docker image for Apiary Data Lake Ranger
Shell
4
star
64

flyte-jira

An Atlassian Jira integration pack for Flyte
Go
4
star
65

pkdd22-challenge-expediagroup

Expedia Group ECML/PKDD 2022 challenge
Python
4
star
66

kafka-consumer-sns-sqs

Kafka Consumer for AWS SNS/SQS
Python
4
star
67

catalyst-render

[DEPRECATED] A hapi js plugin that works with catalyst-server to provide server-side rendering with react inside a handlebars template
JavaScript
4
star
68

nimbuild

A suite of build tools that enable ultra fast web bundling at run-time.
JavaScript
4
star
69

circus-train-datasqueeze

Circus Train ⨉ DataSqueeze
Java
4
star
70

data-highway

Java
4
star
71

expediagroup-python-sdk

Open World SDK for Python
Python
4
star
72

flyte-bamboo

An Atlassian Bamboo integration pack for Flyte
Go
4
star
73

apiary-lifecycle

Terraform deployment scripts for Beekeeper
HCL
4
star
74

housekeeping

Common functionality for managing and cleaning up orphaned paths
Java
3
star
75

icf

Independent connectivity forum API and tools
3
star
76

expediagroup-java-sdk

Expedia Group Java SDK Home
Kotlin
3
star
77

hcommon-hive-metastore

General purpose libraries for interacting with the HiveMetaStore
Java
3
star
78

flyte-shell

Run shell scripts in your Flyte flows with this integration pack
Go
3
star
79

apiary-authorization

Authorization for Apiary Data Lake
HCL
3
star
80

package-json-validator

A Github Action for validating package.json conventions.
TypeScript
3
star
81

flyte-serf

A Hashicorp Serf integration pack for Flyte
Go
3
star
82

network-plugin

The Network plugin allows developers to proxy requests and view the request and responses in IntelliJ.
Kotlin
3
star
83

rapid-java-sdk

ExpediaGroup - Rapid Java SDK Home
Kotlin
3
star
84

a11y-tools

Client side A11y tools for trapping and tracking user focus.
JavaScript
2
star
85

flyte-ldap

An LDAP integration pack for Flyte
Go
2
star
86

new-project

This repository contains a template you can use to seed a repository for a new open source project.
2
star
87

expediagroup-nodejs-sdk

Expedia Group SDK for Node.js
TypeScript
2
star
88

apiary-drone-fly

Terraform scripts for deploying Drone Fly
HCL
2
star
89

expediagroup-java-sdk-parent

2
star
90

parsec

Parsec is a data processing engine for interpreted queries.
Clojure
2
star
91

dropwizard-resilience4j-bundle

Integration of Resilience4J into Dropwizard
Java
2
star
92

renovate-config-catalyst

[DEPRECATED] Renovate shared configuration for catalyst projects
2
star
93

flyte-slack

A Slack integration pack for Flyte
Go
2
star
94

openworld-sdk-java-generators

Mustache
2
star
95

overwhelm

Operator for complex application deployment on Kubernetes
Go
2
star
96

flyte-graphite

A graphite integration pack for Flyte
Go
2
star
97

graphql-kotlin-codegen

A graphql-codegen plugin that enables type generation for GraphQL Kotlin services, promoting schema-first development.
TypeScript
2
star
98

helm-charts

Expedia Group Helm Charts
Mustache
1
star
99

determination

[DEPRECATED] Configuration resolver using confidence and shortstop.
JavaScript
1
star
100

dr-squid

Dr Squid is a downstream services and databases mocking tool primarily used for chaos testing and gathering performance metrics for Java Spring service
Java
1
star