Release your entities

This post shows how to clean JPA entities out of Persistence Context overhead when you need to use them outside of container, serialize them and send them over RMI,  SOAP and other protocols to another JVMs.

The Problem

You may found yourself in a situation where you don't have DTO's, there existing object-graph is large but you need to use entity objects outside of the managed scope. So what is a problem?

In case of Hibernate first problem appears in huge object footprint you'll have to serialize by default even if you send just one detached entity. I found out that at some circumstances nearly the whole Hibernate Context is still connected to your detached entities. If you serializes such an huge but useless object graph every time, you slow down your client, last your network, create huge RMI/Web Service marshaling overhead, wastes client memory which even can provokes out of memory problems. All that you definitely don't need in your application.

Different Solutions

So how to avoid this? We need a simple way to purify given entities at "low cost". Which means the solution has to be simple for developers, with minimal boilerplate code but also be performant at run-time. The output should contain clearly detached and as much as possible purified entities. It's very important to cut any possible references to technical background object of (hibernate) persistent context.

Such cleaning makes only sense outside of the transaction scope. Then at the end of transaction all participated entities have to maintain their persistent state, so of course they cannot be detached before that point. Otherwise detached and pruned entities cannot be persist by entity manager anymore and have to be refreshed first.

Do cleaning outside of transaction scope.

@TransactionAttribute(NEVER)
pubic MyEtity updateMyEntityMethod(MyEntity entity){  
return SomePruner.prune(updateMyEntityMethodTransactional(entity));  
}

@TransactionAttribute(REQUIRED)
protected MyEtity updateMyEntityMethodTransactional(MyEntity entity){  
...
return entityManager.merge(entity);  
}

You can use your updateMyEntityMethod() from outside, this is not transactional. The transaction only begins before updateMyEntityMethodTransactional() method is started and ends after return. The only question is how to minimize the entity footprint as usual several approaches may be used:

Do it yourself. Clone what you need.

  • This is really fast if you do it well. and flexible at all.
  • But blows your code up, and  is hard to maintain.
  • Would you clone even objects you never wrote?

Clone selective by reflection.

  • Can be performant.
  • but need reinvent the wheel, still need to maintain boilerplate code.

Serialize it selective by framework

  • Small footprint.
  • Tends to be less performantly.
  • Can lead to problems with complex graphs (try to serialize bidirectional references to  JSON).

Cloning (reflection based) libraries.

  • Small footprint, easy usage.
  • Very impressive performance
  • Can have restrictions on your design.

I just want to  point out  libraries of the last approach (of course you  invited to discuss alternatives in the comments).

Purify entities by cloning

The cloning library from Kostantinos Kougios is very small, fast configurable and extendable reflection based cloning library. So why not using it for our needs. It just not considered to be an entity pruner out of the box, but this is what i give you here.  Every simple cloner has to look similar:

com.rits.cloning.Cloner cloner=new Cloner();  
MyClass clonedObject=cloner.deepClone(sourceObject);  

This will perform a deep copy of everything, very fast. But what about footprint you ask? You right we don't need everything. Let's tell cloner that we don't want to have hibernate stuff in our clones. Here is an array of classes we don't want to clone.

private final static Class[] SKIPCLASSES = new Class[] {  
  SessionImplementor.class,
  JDBCTransaction.class,
  SessionImpl.class,
  StatelessSessionImpl.class,
  HibernateProxy.class,
JavassistLazyInitializer};

static {  
  cloner = new Cloner();
  cloner.nullInsteadOfClone(SKIPCLASSES);
}

This will clone your entities without Hibernate context. You also encouraged to add additional user-defined classes to this list, if you don't need them in your clones.

The next tip is to use fast cloners. I would use them for top level entities, because you normally don't need all the stuff in the cloned entity. Leaving it at null increases speed (of course we are already at milliseconds). and keep footprint pretty low.

 cloner.registerFastCloner(
 MyServerSideEntity.class, new MyServersideEnitityFastCloner());
 //Beware exact mach of class is used.

So even if cloner is pretty fast out of the box there are several approaches to adapt it to you needs or make it's even more faster. But in the context of JPA entities we have to be more concerned about entity state than maybe about milliseconds of not high optimal cloning. Normally several paths on your object graph will be lazy initialized on transaction end. Let's assume, when something is not initialized at the transaction end, that don't need to be cloned as well. Let manifest this design decision in  the code:

cloner = new Cloner() {  
@Override
protected Object fastClone(Object o, Map<Object, Object> clones)  
                   throws IllegalAccessException {
   //If hibernate proxy collection.
   if (PersistentCollection.class.isAssignableFrom(o.getClass())) {
       if (((PersistentCollection) o).wasInitialized()) {
           return super.fastClone(o,clones());
        }else {
           return null; // or other routine for new empty Object.
        }
    }
   //If hibernate Entityproxy.
   if (HibernateProxy.class.isAssignableFrom(o.getClass())) {
       LazyInitializer initializer = ((HibernateProxy) o).getHibernateLazyInitializer();
        if (!initializer.isUninitialized()) {
             return super.fastClone(initializer.getImplementation(), clones);
        } else {
          return null;
        }
     }
     return super.fastClone(o, clones); //default approach.
   }
};

That's it! Cool isn't?

Entity Pruner

Above solution utilizes general purpose cloning library for Entity pruning, where entity-pruner seems to be more elaborated solution directly for entity pruning and "unpruning" which even deserves to be considered in the initial architecture of the future applications. The adoption of Entity Pruner begins when your entities implement PrunableEntity interface which is used to maintenance of entity prune state. Because of this restriction i downgrade this solution in context of my current problem. But if i would be able to implement such an interface, then i would get  the same performance as by cloning library out of the box.

import com.saliman.entitypruner.EntityPruner;  
 ...
 @Stateless
 SomeFassadeSessionBean
 ...
 @EJB
 EntityPruner pruner;

 @TransactionAttribute(TransactionAttributeType.NEVER)
 public MyEntity getSomeEntity(){
  ...
 return pruner.prune((PrunableEntity)entity);
}

Above you see injected EntityPruner as an EJB. It works because EntityPruner library includes an implementation StatelesBean. It is e.g. hibernate aware implementation. The rest is like cloning library but in additional there is unprune() method which allows to reintegration of received entities to the current persistent context. That makes entity pruner as a complete solution and if you considering usage of entity pruning in the next application maybe it's a best time to look closer on entity pruner now.

DTO vs Entity Pruning

However i can't give you definitive guide to the general question whether DTO's are must in every case or even DTO's are dead since EJB 3.0.

I still think it depends on a situation. But in general usage of DTO's introduces additional abstraction layer, clear and specific interfaces  and therefore increases separation of concerns and flexibility. In opposite to this you have to implement the transformation and maintain DTO's. Let discuss your experiences on this.
Thank you if you read this!