Vlad Mihalcea

  • Home
  • Blog
  • Store
    • Books
    • Courses
    • Hypersistence Optimizer
      • Documentation
        • Installation Guide
        • User Guide
      • Examples
      • Release Notes
      • Issue Tracker
      • Trial Version
      • Full Version
    • Affiliate
  • Training
    • High-Performance Java Persistence
    • High-Performance SQL
    • Spring and Hibernate 6
  • Consulting
    • Coaching
  • Tutorials
    • Hibernate
    • SQL
    • Spring
  • Newsletter
    • Subscribe
    • Videos
    • Talks

 Leave a Comment

Posted on August 24, 2017 by vladmihalcea

How to get the entity mapping to database table binding metadata from Hibernate

Last modified:
Follow @vlad_mihalcea

Imagine having a tool that can automatically detect JPA and Hibernate performance issues. Wouldn’t that be just awesome?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, or Play Framework.

So, enjoy spending your time on the things you love rather than fixing performance issues in your production system on a Saturday night!

You can earn a significant passive income stream from promoting my book, courses, tools, training, or coaching subscriptions.

If you're interested in supplementing your income, then join my affiliate program.

Introduction

Lukas Eder has posted a very interesting question on Stack Overflow, asking about a way of getting access to the binding metadata between entity mappings and database tables.

While I have previously answered a similar question using this article, I realized that particular use case was much simpler since it only extracted the database metadata. In this article, you are going to see how easily you can get the bridge information between your JPA entities and the underlying database schema.

How to get the entity mapping to database table binding metadata from Hibernate@vlad_mihalcea https://t.co/w972BC1ty0 pic.twitter.com/QXrrnYdOuK

— Java (@java) April 23, 2019

Integrator

Hibernate is very flexible, so it defines many SPI (Service Provider Interfaces) that you can register to customize Hibernate internals. One of these interfaces is org.hibernate.integrator.spi.Integrator which is used by many technologies that integrate with Hibernate ORM, like Bean Validation, Envers or JACC Security Provider.

Using the Hibernate Integrator API, we can write our own component that captures the SessionFactory build-time metadata which, otherwise, is only available during bootstrap.

public class MetadataExtractorIntegrator 
    implements org.hibernate.integrator.spi.Integrator {

    public static final MetadataExtractorIntegrator INSTANCE = 
        new MetadataExtractorIntegrator();

    private Database database;

    private Metadata metadata;

    public Database getDatabase() {
        return database;
    }

    public Metadata getMetadata() {
        return metadata;
    }

    @Override
    public void integrate(
            Metadata metadata,
            SessionFactoryImplementor sessionFactory,
            SessionFactoryServiceRegistry serviceRegistry) {

        this.database = metadata.getDatabase();
        this.metadata = metadata;

    }

    @Override
    public void disintegrate(
        SessionFactoryImplementor sessionFactory,
        SessionFactoryServiceRegistry serviceRegistry) {

    }
}

The org.hibernate.boot.Metadata is what we are interested in since it contains the PersistentClass entity bindings.

To register MetadataExtractorIntegrator with Hibernate we have two possibilities based on the underlying bootstrap method.

Hibernate-native boostrap

If you’re using the Hibernate-native bootstrap, then you can register the Integrator with the BootstrapServiceRegistryBuilder as follows:

final BootstrapServiceRegistry bootstrapServiceRegistry = 
    new BootstrapServiceRegistryBuilder()
    .enableAutoClose()
    .applyIntegrator( MetadataExtractorIntegrator.INSTANCE )
    .build();

final StandardServiceRegistry serviceRegistry = 
    new StandardServiceRegistryBuilder(bootstrapServiceRegistry)
    .applySettings(properties())
    .build();

JPA boostrap

If you’re using the JPA bootstrap, then you can register the Integrator with the BootstrapServiceRegistryBuilder as follows:

Map<String, Object> configuration = new HashMap<>();

Integrator integrator = integrator();
if (integrator != null) {
    configuration.put("hibernate.integrator_provider", 
        (IntegratorProvider) () -> Collections.singletonList(
            MetadataExtractorIntegrator.INSTANCE
        )
    );
}

EntityManagerFactory entityManagerFactory = new EntityManagerFactoryBuilderImpl(
    new PersistenceUnitInfoDescriptor(persistenceUnitInfo), 
    configuration
)
.build();

That’s for when you want to bootstrap JPA without any persistence.xml configuration file.

To see how you can set the hibernate.integrator_provider configuration property when using Spring with JPA or Spring with Hibernate, check out this article.

Domain Model

Assuming we have the following database tables mapped by our JPA application:

Database tables

When running the following test case:

Metadata metadata = MetadataExtractorIntegrator.INSTANCE.getMetadata();

for ( PersistentClass persistentClass : metadata.getEntityBindings()) {

    Table table = persistentClass.getTable();
    
    LOGGER.info( "Entity: {} is mapped to table: {}",
                 persistentClass.getClassName(),
                 table.getName()
    );

    for(Iterator propertyIterator = persistentClass.getPropertyIterator(); 
            propertyIterator.hasNext(); ) {
        Property property = (Property) propertyIterator.next();
        
        for(Iterator columnIterator = property.getColumnIterator(); 
                columnIterator.hasNext(); ) {
            Column column = (Column) columnIterator.next();
            
            LOGGER.info( "Property: {} is mapped on table column: {} of type: {}",
                         property.getName(),
                         column.getName(),
                         column.getSqlType()
            );
        }
    }
}

Hibernate generates the following output:

Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$Tag is mapped to table: tag
Property: name is mapped on table column: name of type: varchar(255)
Property: version is mapped on table column: version of type: integer

Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$PostComment is mapped to table: post_comment
Property: post is mapped on table column: post_id of type: bigint
Property: review is mapped on table column: review of type: varchar(255)
Property: version is mapped on table column: version of type: integer

Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$Post is mapped to table: post
Property: title is mapped on table column: title of type: varchar(255)
Property: version is mapped on table column: version of type: integer

Entity: com.vladmihalcea.book.hpjp.util.providers.entity.BlogEntityProvider$PostDetails is mapped to table: post_details
Property: createdBy is mapped on table column: created_by of type: varchar(255)
Property: createdOn is mapped on table column: created_on of type: datetime(6)
Property: version is mapped on table column: version of type: integer

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

And there is more!

You can earn a significant passive income stream from promoting all these amazing products that I have been creating.

If you're interested in supplementing your income, then join my affiliate program.

Conclusion

Hibernate is highly customizable, and the Integrator SPI allows you to get access to the Hibernate Metadata which you can later inspect from your enterprise application.

Follow @vlad_mihalcea
Transactions and Concurrency Control eBook
Earn Passive Income!
High-Performance Java Persistence rocks!
Hypersistence Optimizer rocks!

Related

 Category: Hibernate      Tags: binding, entity, hibernate, metadata, table, Training, Tutorial

← The best way to implement an audit log using Hibernate Envers
The best way to map a projection query to a DTO (Data Transfer Object) with JPA and Hibernate →

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Let’s connect
  • Twitter
  • YouTube
  • LinkedIn
  • Email
  • Facebook
  • Amazon
  • GitHub
Find Article
Book
High-Performance Java Persistence Book
Affiliate
Earn Passive Income!
Video Courses
High-Performance Java Persistence Video Course High-Performance SQL Video Course
Hypersistence Optimizer
Hypersistence Optimizer
Training
Training logo
Localhost Tunneling
LocalXpose
RevoGain
RevoGain - Calculate your trading gains for Kraken and Revolut
Tutorials
  • Hibernate
  • SQL
  • Spring
  • Git
  • FlexyPool
Social Media
  • Twitter
  • Facebook
  • YouTube
  • GitHub
  • LinkedIn
About
  • About
  • FAQ
  • Archive
  • Privacy Policy
  • Terms of Service
Meta
  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Our Cookie Policy

Vlad Mihalcea

Powered by WordPress.com.

 

Loading Comments...