views:

547

answers:

2

I have some classes that represent immutable objects (Quantity, Price, Probability). Is there some way to tell Hibernate that the objects will never change so it can re-use objects rather than creating a new object for every instance of 0 or 1 or Price= $1?

I ended up creating these classes because I discovered that doubles don't do a good job of representing numbers typed by users. Users type numbers in decimal, and if you convert them to doubles, you immediately lose precision (and sometimes correctness). I therefore have replaced all the numbers (other than short-lived ints) with these objects which are based on BigDecimal.

In several previous projects, a major step in performance optimization was caching small numbers, so we weren't creating a new object every time we referred to 0 or 1 or whatever other small numbers were common in the particular project. So I suspect that hibernate would also make sizable savings if it knew it could re-use objects of particular types.

As a matter of clean programming practice, they are pure numbers and immutable, which means the Java code doesn't have to worry about shared objects and side effects. I've defined a few manifest constants for the numbers that are very commonly used in my code, but Hibernate creates a new object for every number it pages in from the DB. (How could it do otherwise? It doesn't know they're immutable, so it can't assume they can be shared.)

At this point I've also turned all these objects into hibernate components, so I don't have to worry about finding and deleting numbers in the database that are no longer used by anything. But that also means there's no longer a Quantity.hbm.xml to put an annotation on, even if hibernate supported such an annotation.

BTW, the most objectionable aspect of this rewrite is that all arithmetic now appears as a.times(b), c.plus(d.minus(e)), etc. But it was a correctness issue more than anything, so I didn't think I had a choice.

+1  A: 

You can tell Hibernate that a specific entity is immutable by using @Entity(mutable=false) or @Immutable annotations. Note that both are Hibernate extensions to JPA standard.

That would not, however, force Hibernate to re-use the objects - it would merely allow for some minor performance optimizations as far as caching / flushing is concerned. Components can't be annotated this way either.

To do what you want you'd have to write your own custom type; you would then be able to have predefined instances for specific (most common) values and return those instead of creating a new instance.

Another alternative is to define a PreLoadEventListener to do that; however entity is already instantiated by the time your listener is called so you'd only be able to replace it with your instance.

ChssPly76
custom types seem like a plausible solution. The objects do get rebuilt as individual objects, even though they're stored as components. Are there appropriate hooks for custom types to be able to provide a cached object rather than building a new one?
PanCrit
There are no hooks per se - you have complete control over what you doing. You'll need to implement `UserType` interface (http://docs.jboss.org/hibernate/stable/core/api/org/hibernate/usertype/UserType.html); `nullSafeGet()` method will be invoked to load your value. You can return a pre-defined instance from it instead of creating a new one.
ChssPly76
A: 

Take advantage of the Hibernate second level cache. For immutable objects like the ones you described you will want to use the read-only cache strategy. I've used the second level cache in a few applications and it made a huge performance improvement. It is worth spending the time to truly understand the ramifications of caching so I highly recommend you read the Hibernate docs on the second level cache:

Hibernate Second level cache

Rob Smith
Cache is only applicable to **entities**. That's not what OP is asking
ChssPly76