At some point, every developer starts using an external library. They then have to decide if that external library should be wrapped in their own custom interfaces and classes.
If the external library would be pervasively imported in throughout the code then the answer is empathically YES — the external library should be wrapped.
At Amplafi, hibernate is just such a library. Without wrapping every time the hibernate library changed its structure or behavior, the change would have a large impact. However, by wrapping the libraries hibernate became loosely coupled.
This also enabled us to solve other more major issues with Hibernate Query and Session.
- control when a transaction could be committed. We wanted to count how many times a tx was “started” and only commit when the tx was “ended” the same number of times it was started. Useful for code that doesn’t know if it needs to start a transaction. Now any code that needs a tx just “starts” one and ends it when done.
- Performance metrics gathering.
- Delaying starting the transaction until it is known that something will actually be done.
More gentle behavior for query.uniqueResult() ( default Hibernate behavior is to throw an exception if there is more than one row returned. Amplafi’s wrapper logs the non-uniqueness + ids of the extra rows. )
How we did this:
- Create an interface (AmplafiQuery) that extends Query
- Create a class (AmplafiQueryImpl) that extends AmplafiQuery and wraps a org.hibernate.Query
- Create a Txmanager that returns a Tx.
- Tx has the various createQuery methods and returns AmplafiQuery
We also took the opportunity to add to AmplafiQuery:
- a “asList()” that is a generic enabled version of Query.list()
- a “unique()” that is a generic enabled version of Query.uniqueResult()