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 a bit wide-spreading  but you need to use entity objects outside of the managed scope. So where is a problem? In case of Hibernate first problem appears is huge  object footprint you’ll have to serialize by default  even if you send just one detached entity. I found 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  slows down your client,  last your  network, creates huge RMI/Web Service marshalling overhead,  wastes client memory which even can provokes out of memory problems.  All that you 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 and also 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 baground object of (hibernate) persistent context.

Before you start you have to be clear about  that such cleaning makes sense only outside of  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.

However you don’t have to weak transactional behavior, just do cleaning outside of transactional scope. In container managed transaction environment it simply achieved by annotations. 

@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. Notify that the pruning of the entity is done outside of the transaction. The only question is how to lowerage the real existing entity footprint  as usual several approaches may be used:

Do it by yourself. Clone what you need.

Clone selective by reflection.

Serialize it selective by framework

Cloning (reflection based) libraries.

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

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);
}

Abowe 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!

If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.

Comments

Gilead is a project that is focused entirely on the hibernate / JPA entities -> pruned-DTO-for-serialization. For cases where you ARE using DTOs, using an existing project for that works well.

Thank you. Gilead looks to me very similar to Entity Pruner.

Leave a comment

(required)

(required)