JBULL SourceForge.net Logo

Overview

JBULL is a very simple library for standard/mostly used java bean operations. Such operations are copy, clone, equality. It is interesting that such operations are not provided by standard J2SE.

There are already some open source projects that cover this simple topic. Unfortunately performance they offer is really disappointing.

Warning! This documentation is still in construction

Whole the project is still in early beta phase. It means it works for me but I wish it worked for anybody else. I am awaiting comments and issues. I strongly insist on not using it (yet) in mission critical projects!

For additional information see sourceforge project page.

Usage

This lib provides two basic operations:

BeanHelper.copy(Object src, Object dst)
BeanHelper.equals(Object src, Object dst)

BeanHelper.copy(Object src, Object dst)

This is the easiest way to perform copy operation. Lets check example:

                    MyClassOne sourceBean = .... // this is  source bean
                    MyOtherClass destBean = new MyOtherClass(); // this is target bean
                    ...
                    BeanHelper.copy(sourceBean, destBean); //this is copy operation
                

Copy for java beans means: copy all valid java beans properties. There are no restrictions on any dependencies between target and source classes (neither inheritance nor common interface is needed).

Performance note: Introspection is known to be time consuming - and it really is. In order to provide fastest possible speed this method uses some caching. However, it does not simply cache introspection result, but in fact it stores the ready list of primitive method.invoke operations that are needed to perform desired high-level operation !!!

BeanHelper.getWorker(T src, U dst)

The mentioned, cached set of operation can be stored as BeanWorker (operation object). This there are checks against cache avoided. Which proved to give some measurable speed improvement.

Example:

                    /**
                    * this field stores worker
                    */
                    private final BeanWorker< MyClassOne, MyOtherClass> worker = 
                    BeanHelper.getWorker(MyClassOne.class,MyOtherClass.class );
                    ....         
                    
                    {        
                    MyClassOne sourceBean = .... // this is  source bean
                    MyOtherClass destBean = new MyOtherClass(); // this is target bean
            
           
                    ...
                    this.worker.copy( sourceBean, destBean);    
                    ...
                    }
                

BeanHelper.getStaticWorker

how to get probably fastest possible speed

This feature is experimental -> it works but the way it works may change. Especially that current aproach is very dangerous and may be unpredictable under some circumstances!!!

Although, getWorker brings really huge speed - it is sure that set of reflective calls (Method.invoke ) will be usually slower (not faster) than simple compiled code with set of dst.setXYZ (src.getXYZ() ); operations.

hanks to the newest cool features of JAVA 5.0 it was possible to introduce simple code generator for beans operations. In order to use it developer has to do some additional tasks:

            
                    public  class MyClass { ...
                    /**
                    * this field stores STATIC worker
                    */
                    @StaticCopier
                    private final BeanWorker< MyClassOne, MyOtherClass> worker = 
                    BeanHelper.findStaticWorker(MyClass.class);
                    ....         
                    
                    {        
                    MyClassOne sourceBean = .... // this is  source bean
                    MyOtherClass destBean = new MyOtherClass(); // this is target bean
            
           
                    ...
                    this.worker.copy( sourceBean, destBean);    
                    ...
                    }
                

Not so many things have changed in this code. It is important to know that this method will be working also if apt task was not performed during the build - or if it has failed. In such case - normal runtime worker will be created (@todo!!). This means that it is easy to turn it on or off and check the impact on performance during for instance project testing phase!!! Only the build process has to be changed.

BeanHelper.create and BeanHelper.dispose

You those operations to create per thread helper. And to dispose memory consumed by workers cache.

SynchronizedBeanHelper

You this for thread safe operations.

Annotations

@todo: write about defined annotation

Filters

@todo: write about custom filters

Exceptions

@todo:

Plans - todo

List of things I plan to do in order to call this product version 1.0:

Future plans:

Javadoc

API

Download

Please, go to sourceforge project page.

Goals

Benchmarks

microbenchmark in fact

method time (ms)
BeanHelper.copy
simple
17594
BeanWorker.copy()
stored worker
6563
.copy()
Custom copy method (written)
78
staticCopy
Generated copy method (APT)
78
other libraries
dozer 458594
beanlib 519547
beanutils 1584875
beanutils2 563375

Test machine: Pentium 4 3GHZ,HT, 1GB RAM
JVM: Java HotSpot(TM) Server VM (build 1.5.0_04-b05, mixed mode)
JVM args: -server -Xmx128m -Xms128m -XX:CompileThreshold=100
See CopyBenchmarkTest.class for details.

There were 9999999 basic operations performed, before each measured loop there was small loop with 9999 operations called.

As I wanted to test my framework from the begining there is set of benchmarks ready -> see tests package. I compared my solution to other: beanlib, commons-beanutils. Although benchmark may suggest my solution is a "hell" faster I do not say that ( :-) ):

Comments on benchmarks

expected
my lib perfomance speed is at least good compared to others :-)
surprise
Pregenerated code does not give as much as I expected, and this realy depends on JVM version and config (possibly Method.invoke is not as bad as people tend to say), although there is still some speed improvement, so this can always be an option. Above tests may suggest that generated code is 100 times faster. On the other hand, it is visible generated code spares 1ms per 1000 operations. For typical J2EE project it may be not worth to complicate build and debug only to gain this 1ms. !!!
big surprise!!!
checking for cache appeared to be quite costly - so it is strongly advised to keep "BeanWorkers" (in static variables) - this way it is possible to replace them with generated code later.