HHH-15170 - Dedicated chapter for "Build Tool Support"

This commit is contained in:
Steve Ebersole 2022-04-04 19:15:15 -05:00
parent 0df4dc1642
commit 9d3726e39d
7 changed files with 136 additions and 94 deletions

View File

@ -32,6 +32,7 @@ include::chapters/envers/Envers.adoc[]
include::chapters/beans/Beans.adoc[] include::chapters/beans/Beans.adoc[]
include::chapters/portability/Portability.adoc[] include::chapters/portability/Portability.adoc[]
include::chapters/statistics/Statistics.adoc[] include::chapters/statistics/Statistics.adoc[]
include::chapters/tooling/Tooling.adoc[]
include::appendices/Configurations.adoc[] include::appendices/Configurations.adoc[]
include::appendices/Annotations.adoc[] include::appendices/Annotations.adoc[]

View File

@ -8,13 +8,11 @@ Hibernate 3.x saw the first attempts at bytecode enhancement support in Hibernat
We consider those initial attempts (up until 5.0) completely as an incubation. We consider those initial attempts (up until 5.0) completely as an incubation.
The support for bytecode enhancement in 5.0 onward is what we are discussing here. The support for bytecode enhancement in 5.0 onward is what we are discussing here.
[[BytecodeEnhancement-capabilities]] See <<tooling-enhancement>> for discussion of performing enhancement.
==== Capabilities
Hibernate supports the enhancement of an application Java domain model for the purpose of adding various persistence-related capabilities directly into the class.
[[BytecodeEnhancement-lazy-loading]] [[BytecodeEnhancement-lazy-loading]]
===== Lazy attribute loading ==== Lazy attribute loading
Think of this as partial loading support. Think of this as partial loading support.
Essentially, you can tell Hibernate that only part(s) of an entity should be loaded upon fetching from the database and when the other part(s) should be loaded as well. Essentially, you can tell Hibernate that only part(s) of an entity should be loaded upon fetching from the database and when the other part(s) should be loaded as well.
@ -46,7 +44,7 @@ The plan is to relax that requirement later.
==== ====
[[BytecodeEnhancement-dirty-tracking]] [[BytecodeEnhancement-dirty-tracking]]
===== In-line dirty tracking ==== In-line dirty tracking
Historically Hibernate only supported diff-based dirty calculation for determining which entities in a persistence context have changed. Historically Hibernate only supported diff-based dirty calculation for determining which entities in a persistence context have changed.
This essentially means that Hibernate would keep track of the last known state of an entity in regards to the database (typically the last read or write). This essentially means that Hibernate would keep track of the last known state of an entity in regards to the database (typically the last read or write).
@ -59,7 +57,7 @@ In this approach Hibernate will manipulate the bytecode of your classes to add "
During the flush time, Hibernate asks your entity what has changed rather than having to perform the state-diff calculations. During the flush time, Hibernate asks your entity what has changed rather than having to perform the state-diff calculations.
[[BytecodeEnhancement-dirty-tracking-bidirectional]] [[BytecodeEnhancement-dirty-tracking-bidirectional]]
===== Bidirectional association management ==== Bidirectional association management
Hibernate strives to keep your application as close to "normal Java usage" (idiomatic Java) as possible. Hibernate strives to keep your application as close to "normal Java usage" (idiomatic Java) as possible.
Consider a domain model with a normal `Person`/`Book` bidirectional association: Consider a domain model with a normal `Person`/`Book` bidirectional association:
@ -96,74 +94,8 @@ include::{sourcedir}/BytecodeEnhancementTest.java[tags=BytecodeEnhancement-dirty
Bytecode-enhanced bi-directional association management makes that first example work by managing the "other side" of a bi-directional association whenever one side is manipulated. Bytecode-enhanced bi-directional association management makes that first example work by managing the "other side" of a bi-directional association whenever one side is manipulated.
[[BytecodeEnhancement-dirty-tracking-optimizations]] [[BytecodeEnhancement-dirty-tracking-optimizations]]
===== Internal performance optimizations ==== Internal performance optimizations
Additionally, we use the enhancement process to add some additional code that allows us to optimized certain performance characteristics of the persistence context. Additionally, we use the enhancement process to add some additional code that allows us to optimize certain performance
These are hard to discuss without diving into a discussion of Hibernate internals. characteristics of the persistence context. These are hard to discuss without diving into a discussion of Hibernate internals.
[[BytecodeEnhancement-enhancement]]
==== Performing enhancement
[[BytecodeEnhancement-enhancement-runtime]]
===== Runtime enhancement
Currently, runtime enhancement of the domain model is only supported in managed Jakarta Persistence environments following the Jakarta Persistence-defined SPI for performing class transformations.
Even then, this support is disabled by default. To enable runtime enhancement, specify one of the following configuration properties:
`*hibernate.enhancer.enableDirtyTracking*` (e.g. `true` or `false` (default value))::
Enable dirty tracking feature in runtime bytecode enhancement.
`*hibernate.enhancer.enableLazyInitialization*` (e.g. `true` or `false` (default value))::
Enable lazy loading feature in runtime bytecode enhancement. This way, even basic types (e.g. `@Basic(fetch = FetchType.LAZY`)) can be fetched lazily.
`*hibernate.enhancer.enableAssociationManagement*` (e.g. `true` or `false` (default value))::
Enable association management feature in runtime bytecode enhancement which automatically synchronizes a bidirectional association when only one side is changed.
[NOTE]
====
Also, at the moment, only annotated classes support runtime enhancement.
====
[[BytecodeEnhancement-enhancement-gradle]]
===== Gradle plugin
Hibernate provides a Gradle plugin that is capable of providing build-time enhancement of the domain model as they are compiled as part of a Gradle build.
To use the plugin, a project would first need to apply it:
.Apply the Gradle plugin
====
[source,gradle]
----
include::extras/gradle-example.gradle[]
----
====
The configuration that is available is exposed through a registered Gradle DSL extension:
enableLazyInitialization:: Whether enhancement for lazy attribute loading should be done.
enableDirtyTracking:: Whether enhancement for self-dirty tracking should be done.
enableAssociationManagement:: Whether enhancement for bi-directional association management should be done.
The default value for all 3 configuration settings is `false`.
The `enhance { }` block is required in order for enhancement to occur.
Enhancement is disabled by default in preparation for additions capabilities (hbm2ddl, etc) in the plugin.
[[BytecodeEnhancement-enhancement-maven]]
===== Maven plugin
Hibernate provides a Maven plugin capable of providing build-time enhancement of the domain model as they are compiled as part of a Maven build.
See the section on the <<BytecodeEnhancement-enhancement-gradle>> for details on the configuration settings. Again, the default for those 3 is `false`.
The Maven plugin supports one additional configuration settings: failOnError, which controls what happens in case of error.
The default behavior is to fail the build, but it can be set so that only a warning is issued.
.Apply the Maven plugin
====
[source,xml]
----
include::extras/maven-example.pom[]
----
====

View File

@ -1,19 +0,0 @@
apply plugin: 'org.hibernate.orm'
ext {
hibernateVersion = 'hibernate-version-you-want'
}
buildscript {
dependencies {
classpath "org.hibernate:hibernate-gradle-plugin:$hibernateVersion"
}
}
hibernate {
enhance {
enableLazyInitialization = true
enableDirtyTracking = true
enableAssociationManagement = true
}
}

View File

@ -0,0 +1,90 @@
[[tooling]]
== Build Tool Integration
Hibernate provides a few build-time services available as plugins for
https://gradle.org[Gradle], https://maven.org[Maven] and https://ant.org[Ant].
These services include -
* Bytecode enhancement
* Schema management
* Static Metamodel generation
[[tooling-enhancement]]
=== Bytecode Enhancement
Hibernate performs bytecode enhancement through its `org.hibernate.bytecode.enhance.spi.Enhancer`
contract. These build time tools provide a way to incorporate configuration and execution of
the enhancer into a build.
See <<BytecodeEnhancement>> for discussion of the capabilities of an enhanced model.
[NOTE]
====
At the moment, only annotated classes are supported for enhancement.
====
[[tooling-enhancement-runtime]]
==== Runtime Bytecode Enhancement
Hibernate can also perform run-time bytecode enhancement when used in Jakarta EE compliant
containers through `jakarta.persistence.spi.ClassTransformer`. See the documentation of
your container for any additional details. Run-time enhancement is controlled through
3 true/false settings (all of which default to false):
`hibernate.enhancer.enableDirtyTracking`:: Whether to enhance the model for dirty-tracking
`hibernate.enhancer.enableLazyInitialization`:: Whether to enhance the model for lazy loading at the attribute level. This allows
even basic types to be fetched lazily. It also allows definition of fetch groups (`LazyGroup`).
`hibernate.enhancer.enableAssociationManagement`:: Whether to automatically synchronize a bidirectional association when only one side is changed.
[[tooling-schema]]
=== Schema Management
[[tooling-modelgen]]
=== Static Metamodel Generation
[[tooling-gradle]]
=== Gradle Plugin
For integrating with Gradle, Hibernate provides the
https://plugins.gradle.org/plugin/org.hibernate.orm[org.hibernate.orm] plugin which
supports bytecode enhancement and static metamodel generation but not schema tooling.
[source,gradle]
----
include::extras/gradle-example.gradle[]
----
[[tooling-maven]]
=== Maven Plugin
Hibernate provides a Maven plugin capable of providing build-time enhancement of the domain
model as they are compiled as part of a Maven build. See the section on the
<<BytecodeEnhancement-enhancement-gradle>> for details on the configuration settings. Again, the default for those 3 is `false`.
The Maven plugin supports one additional configuration settings: failOnError, which controls what happens in case of error.
The default behavior is to fail the build, but it can be set so that only a warning is issued.
.Apply the Maven plugin
====
[source,xml]
----
include::extras/maven-example.pom[]
----
====
[[tooling-ant]]
=== Ant Plugin
todo - https://hibernate.atlassian.net/browse/HHH-15171

View File

@ -0,0 +1,23 @@
plugins {
// e.g., let's use the 6.0.0.Final version of the plugin
id "org.hibernate.orm" version "6.0.0.Final"
}
hibernate {
enhancement {
// all default to false
lazyInitialization true
dirtyTracking true
associationManagement true
}
jpaMetamodel {
// defaults to true
applyGeneratedAnnotation true
// defaults to ['raw', 'deprecation']
suppress 'raw'
// defaults to `${buildDir}/generated/sources/jpaMetamodel
generationOutputDirectory "${buildDir}/generated/sources/modelgen"
// defaults to `${buildDir}/classes/java/jpaMetamodel
compileOutputDirectory "${buildDir}/classes/java/modelgen"
}
}

View File

@ -29,6 +29,7 @@ public class JpaMetamodelGenerationSpec {
public static final String DSL_NAME = JPA_METAMODEL; public static final String DSL_NAME = JPA_METAMODEL;
private final Property<Boolean> applyGeneratedAnnotation; private final Property<Boolean> applyGeneratedAnnotation;
private final Project project;
private final SetProperty<String> suppressions; private final SetProperty<String> suppressions;
private final DirectoryProperty generationOutputDirectory; private final DirectoryProperty generationOutputDirectory;
private final DirectoryProperty compileOutputDirectory; private final DirectoryProperty compileOutputDirectory;
@ -38,6 +39,8 @@ public class JpaMetamodelGenerationSpec {
@Inject @Inject
@SuppressWarnings( "UnstableApiUsage" ) @SuppressWarnings( "UnstableApiUsage" )
public JpaMetamodelGenerationSpec(HibernateOrmSpec ormDsl, Project project) { public JpaMetamodelGenerationSpec(HibernateOrmSpec ormDsl, Project project) {
this.project = project;
applyGeneratedAnnotation = project.getObjects().property( Boolean.class ); applyGeneratedAnnotation = project.getObjects().property( Boolean.class );
applyGeneratedAnnotation.convention( true ); applyGeneratedAnnotation.convention( true );
@ -78,11 +81,23 @@ public class JpaMetamodelGenerationSpec {
return suppressions; return suppressions;
} }
public void suppress(String warning) {
suppressions.add( warning );
}
public DirectoryProperty getGenerationOutputDirectory() { public DirectoryProperty getGenerationOutputDirectory() {
return generationOutputDirectory; return generationOutputDirectory;
} }
public void generationOutputDirectory(Object ref) {
generationOutputDirectory.set( project.file( ref ) );
}
public DirectoryProperty getCompileOutputDirectory() { public DirectoryProperty getCompileOutputDirectory() {
return compileOutputDirectory; return compileOutputDirectory;
} }
public void compileOutputDirectory(Object ref) {
compileOutputDirectory.set( project.file( ref ) );
}
} }