building Metadata multiple times makes EnversService throw an UnsupportedOperationException

Description

building MetaData a second time for an existing ServiceRegistry, e.g. via
new MetadataSources(myServiceRegistry).getMetadataBuilder().build()
fails with:

test case app based on envers-5 template: https://github.com/zyro23/hhh-12089

thanks, zyro

Activity

Show:

zyro November 14, 2017 at 3:44 PM

agreed. thx.

Chris Cranford November 14, 2017 at 3:42 PM

is that the recommended approach, i.e. should re-building the Metadata be avoided?

The main issue with executing the build process again is that you're effectively doing double work. This causes Hibernate to parse annotations, hbm xml files, and for Envers to rebuild and create all the necessary audit hbm xml configurations again. Based on your domain model size, this could introduce some overhead in memory and performance.

or is there any specific reason why envers does not allow it?

The primary reason is that the current EnversService is registered as a global-service in the StandardServiceRegistry. It maintains a bit of state about the audited entities it generates by interpreting the Hibernate Metadata and so rebuilding the Metadata would override the service's global state; hence why the guard exists to avoid this potential pitfall.

With that said, I would say you have 2 alternatives:

  1. org.hibernate.integrator.spi.Integrator

  2. org.hibernate.boot.spi.MetadataContributor

The Integrator contract is ideal if you're needing a fully built Metadata instance that has had all second passes, other MetadataContributor contributions, and Envers contributions added. But if you're looking for a step in the build process to perhaps mutate the Metadata prior to second passes and Envers contributions, then a MetadataContributor is a great spot.

With that I am going to close this issue as I think one of the above alternatives make more sense logically.

zyro November 13, 2017 at 4:12 PM

we are using a framework (Grails/GORM) that takes care of the hibernate initialization and a few plugins which re-build the Metadata (for the existing SessionFactory) at runtime, after the initial bootstrapping already happened, in order to allow to introspect the Metadata.

this works fine as long as envers is not in use because of this guard: https://github.com/hibernate/hibernate-orm/blob/5.2.12/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java#L108

i also read https://vladmihalcea.com/2017/08/24/how-to-get-the-entity-mapping-to-database-table-binding-metadata-from-hibernate which suggests using an Integrator to capture and expose the built Metadata.

is that the recommended approach, i.e. should re-building the Metadata be avoided?
or is there any specific reason why envers does not allow it?

thanks for your feedback!

Chris Cranford November 13, 2017 at 3:30 PM

Is there a particular reason why you need to build the MetadataSources with an existing ServiceRegistry that is associated with a fully functional SessionFactory?

I would have expected that if you needed to do something like this that you would have built a new ServiceRegistry and used it like all the other tests in `hibernate-core`:

Rejected

Details

Assignee

Reporter

Components

Affects versions

Priority

Created November 11, 2017 at 12:41 PM
Updated November 14, 2017 at 3:44 PM
Resolved November 14, 2017 at 3:43 PM