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

HHH-15171 - Add discussion of the Ant Plugin
This commit is contained in:
Steve Ebersole 2022-04-05 15:24:45 -05:00
parent cf152d57b1
commit 17bb4aa066
20 changed files with 507 additions and 700 deletions

View File

@ -1,442 +0,0 @@
[[jpamodelgen-guide]]
= Jakarta Persistence Static Metamodel Generator
:imagesdir: images
:version: {fullVersion}
:toc:
[[whatisit]]
== What is it about?
Jakarta Persistence defines a typesafe Criteria API which allows `Criteria` queries
to be constructed in a strongly-typed manner, utilizing so called
static metamodel classes.
For developers it is important that the task of the metamodel generation
can be automated.
Hibernate Static Metamodel Generator is an annotation processor based on
https://jcp.org/en/jsr/detail?id=269[JSR_269] with the task of creating Jakarta Persistence 2
static metamodel classes.
The following example shows two native-bootstrap entities `Order` and `Item`, together
with the metamodel class `Order_` and a typesafe query.
[[jpa2-entity-example]]
.Jakarta Persistence annotated entities `Order` and `Item`
====
[source, JAVA]
----
@Entity
public class Order {
@Id
@GeneratedValue
Integer id;
@ManyToOne
Customer customer;
@OneToMany
Set<Item> items;
BigDecimal totalCost;
// standard setter/getter methods
...
}
@Entity
public class Item {
@Id
@GeneratedValue
Integer id;
int quantity;
@ManyToOne
Order order;
// standard setter/getter methods
...
}
----
====
[[metamodel-class-example]]
.Metamodel class Order_
====
[source, JAVA]
----
@StaticMetamodel(Order.class)
public class Order_ {
public static volatile SingularAttribute<Order, Integer> id;
public static volatile SingularAttribute<Order, Customer> customer;
public static volatile SetAttribute<Order, Item> items;
public static volatile SingularAttribute<Order, BigDecimal> totalCost;
}
----
====
[[criteria-example]]
.Typesafe citeria query
====
[source, JAVA]
----
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Order> cq = cb.createQuery(Order.class);
SetJoin<Order, Item> itemNode = cq.from(Order.class).join(Order_.items);
cq.where( cb.equal(itemNode.get(Item_.id), 5 ) ).distinct(true);
----
====
[TIP]
====
Hibernate Static Metamodel Generator also takes into consideration xml
configuration specified in `orm.xml` or mapping files specified in
`persistence.xml`. However, if XML is your only configuration source,
you need to add in at least on of the mapping file the following
persistence unit metadata:
----
<persistence-unit-metadata>
<xml-mapping-metadata-complete/>
</persistence-unit-metadata>
----
====
== Canonical Metamodel
The structure of the metamodel classes is described in the Jakarta Persistence
(JSR 317) https://jcp.org/en/jsr/detail?id=317[specification], but for
completeness the definition is repeated in the following paragraphs.
Feel free to skip ahead to the <<chapter-usage,usage chapter>>, if you
are not interested into the gory details.
The annotation processor produces for every managed entity in the
persistence unit a metamodel class based on these rules:
* For each managed class X in package p, a metamodel class X_ in
package p is created.
* The name of the metamodel class is derived from the name of the
managed class by appending "_" to the name of the managed class.
* The metamodel class X_ must be annotated with the
`jakarta.persistence.StaticMetamodel` annotation.
* If class X extends another class S, where S is the most derived
managed class (i.e., entity or mapped superclass) extended by X, then
class X_ must extend class S_, where S_ is the metamodel class created
for S.
* For every persistent non-collection-valued attribute y declared by
class X, where the type of y is Y, the metamodel class must contain a
declaration as follows:
public static volatile SingularAttribute<X, Y> y;
* For every persistent collection-valued attribute z declared by class
X, where the element type of z is Z, the metamodel class must contain
a declaration as follows:
** if the collection type of z is java.util.Collection, then
public static volatile CollectionAttribute<X, Z> z;
** if the collection type of z is java.util.Set, then
public static volatile SetAttribute<X, Z> z;
** if the collection type of z is java.util.List, then
public static volatile ListAttribute<X, Z> z;
** if the collection type of z is java.util.Map, then
+
public static volatile MapAttribute<X, K, Z> z;
+
where K is the type of the key of the map in class X
Import statements must be included for the needed `jakarta.persistence.metamodel` types as
appropriate and all classes X, Y, Z, and K.
[[chapter-usage]]
== Usage
The jar file for the annotation processor can be found in the
https://search.maven.org/[Maven Central repository] under:
====
[source, XML]
[subs="verbatim,attributes"]
----
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>{version}</version>
</dependency>
----
====
Alternatively, it can be found in the ORM distribution bundle on
https://sourceforge.net/projects/hibernate/files/hibernate-orm/[SourceForge].
In most cases the annotation processor will automatically run provided
the processor jar is added to the build classpath.
This happens due to Java's Service Provider contract and the fact
the Hibernate Static Metamodel Generator jar files contains the
file _javax.annotation.processing.Processor_ in the _META-INF/services_ directory.
The fully qualified name of the processor itself is:
`org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor`.
=== Usage from the command line
[[usage-ant]]
==== Usage with Ant
As mentioned above, the annotation processor will run automatically
each time the Java compiler is called, provided the jar file is on the
classpath.
Sometimes, however, it is useful to control the annotation
processing in more detail, for example if you exclusively want to run
the processor without compiling any other source files.
The <<javac-task-example,Javac task>> configuration below shows how
Ant can be configured to just run annotation processing.
[[javac-task-example]]
.Javac Task configuration
====
[source, XML]
----
<javac srcdir="${src.dir}"
destdir="${target.dir}"
failonerror="false"
fork="true"
classpath="${classpath}">
<compilerarg value="-proc:only"/>
</javac>
----
====
The option _-proc:only_ instructs the compiler to just run the annotation processing.
You can also completely disable processing by specifying _-proc:none_.
[TIP]
====
Run `'javac -help'` to see which other annotation processor relevant
options can be specified.
====
==== Usage with Maven
There are several ways of running the annotation processor as part of a Maven build.
Again, it will automatically run if you are compiling with a JDK >6.
In case you have more than one annotation processor on your classpath you can explicitly
pass the processor option to the compiler plugin:
.Maven compiler plugin configuration - direct execution
====
[source, XML]
----
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
</plugin>
----
====
The maven-compiler-plugin approach has the disadvantage that the maven compiler plugin
does currently not allow to specify multiple compiler arguments
(https://jira.codehaus.org/browse/MCOMPILER-62[MCOMPILER-62])
and that messages from the Messenger API are suppressed
(https://jira.codehaus.org/browse/MCOMPILER-66[MCOMPILER-66]).
A better approach is to disable annotation processing for the compiler
plugin as seen in below.
[[disable-processing-maven-compiler-plugin]]
.Maven compiler plugin configuration - indirect execution
====
[source, XML]
----
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgument>-proc:none</compilerArgument>
</configuration>
</plugin>
----
====
Once disabled, the https://bsorrentino.github.io/maven-annotation-plugin/[maven-processor-plugin]
for annotation processing can be used:
[[maven-processor-plugin]]
.Configuration with maven-processor-plugin
====
[source, XML]
[subs="verbatim,attributes"]
----
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.0.5</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<processors>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</processors>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>{version}</version>
</dependency>
</dependencies>
</plugin>
----
====
Another possibility is to supply the dependency as an annotation processor path to the maven-compiler-plugin:
[[maven-compiler-plugin]]
.Configuration with maven-compiler-plugin
====
[source, XML]
[subs="verbatim,attributes"]
----
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>{fullVersion}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
----
====
=== Usage within the IDE
Of course you also want to have annotation processing available in your favorite IDE. The
following paragraphs and screenshots show you how to enable the Hibernate Static Metamodel
Generator within your IDE.
==== Idea
Intellij Idea contains from version 9.x onwards a specific configuration section for
annotation processing under the project settings window.
The screenshots show you how to configure the Hibernate Static Metamodel Generator.
image:idea-annotation-processor-config.png[]
In the annotation processor configuration, enable annotation processing and select obtain
from project classpath.
Add the annotation processor name `org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor`
(and optionally the annotation processor options).
Select the module(s) containing your entities.
If you have configured Maven as recommended, it is best to select the same output directory
for the generated classes.
At the time of writing, it is _target/generated-sources/apt_. That way, the generated
classes will be available in IntelliJ Idea.
==== Eclipse
In Eclipse exists also an additional configuration section under Java Compiler.
There you can configure all kinds of aspects of annotation processing.
Just check the "Enable annotation processing" option, configure the directory for the
generated sources and finally add the Hibernate Static Metamodel Generator and Jakarta Persistence jar
files to the factory path.
image:eclipse-annotation-processor-config.png[]
=== Processor specific options
The Hibernate Static Metamodel Generator accepts a series of custom
options which can be passed to the processor in the format: `-A[property]=[value]`
The supported properties can be found in the table below:
.Hibernate Static Metamodel Generator options
|===============
|*Option name* | *Option value and usage*
|debug | If set to `true` additional trace
information will be outputted by the processor
|persistenceXml | Per default the processor looks in
_/META-INF_ for persistence.xml. Specifying
this option a _persitence.xml_ file from a
different location can be specified
(has to be on the classpath)
|ormXml | Allows to specify additional entity mapping
files. The specified value for this option is a
comma separated string of mapping file names.
Even when this option is specified
_/META-INF/orm.xml_ is implicit.
|lazyXmlParsing | Possible values are `true` or `false`. If set to
`true` the annotation processor tries to
determine whether any of the xml files has
changed between
invocations and if unchanged skips the xml parsing.
This feature is experimental and contains the risk
of wrong results in some cases of mixed mode
configurations. To determine wether a file has
been modified a temporary file
`Hibernate-Static-Metamodel-Generator.tmp`
is used. This file gets created in the
`java.io.tmpdir` directory.
|fullyAnnotationConfigured | If set to `true` the processor will
ignore `orm.xml` and `persistence.xml`.
|addGeneratedAnnotation | If set to `true` the processor will
add the @Generated to the generated
Java source file. Adding this annotation using
JDK 5 will cause a compilation error. In this
case set the flag to false. The default for this option is `true`
|addGenerationDate | If set to true the generation date
of the metamodel class will be inserted in the
date parameter of the @Generated annotation.
The default is `false`. This parameter is
ignored if _addGeneratedAnnotation_ is set
to _false_.
|addSuppressWarningsAnnotation| If set to `true` the processor will
add `@SuppressWarnings("all")` to the
generated Java source file. Per default this
annotation is not generated. See also https://hibernate.onjira.com/browse/METAGEN-50[METAGEN-50].
|===============

View File

@ -1,132 +0,0 @@
[[custom-sf-session-guide]]
= Custom SessionFactory and Session Implementations Guide
:toc:
The two main contracts of Hibernate, `org.hibernate.SessionFactory` and `org.hibernate.Session`, are both
defined as interfaces which allows for custom implementations to be provided. There are two high-level ways
in which custom implementations can be provided to users. The first is to develop a custom bootstrap API
specific to the custom implementation. The second way is to integrate with the Hibernate bootstrap API.
This guide will cover the second approach.
== Implementor contracts
A Hibernate naming convention is that SPI contracts extending API contracts are named with Implementor appended
to the API contract name. For `SessionFactory` and `Session` that is `SessionFactoryImplementor` and
`SessionImplementor` respectively. These SPI contracts extra information and functionality needed by internal
components as well as other SPI components. Therefore, custom `SessionFactory` and `Session` should additionally
implement `org.hibernate.engine.spi.SessionFactoryImplementor` and `org.hibernate.engine.spi.SessionImplementor`.
See all pertinent JavaDocs for discussions of implementation details.
== Integration hooks
`org.hibernate.boot.SessionFactoryBuilder` is part of the Hibernate native bootstrap API where we want to configure
the `SessionFactory` to be built. Third parties can hook into this process by supplying a
`org.hibernate.boot.spi.SessionFactoryBuilderFactory` via the Java ServiceLoader mechanism (see JavaDocs for
`java.util.ServiceLoader` if you are unfamiliar with this service discovery mechanism). As you might guess from their
names, a `SessionFactoryBuilderFactory` is responsible for creating `SessionFactoryBuilder` instances and a
`SessionFactoryBuilder` is in turn responsible for creating `SessionFactory` instances.
`org.hibernate.boot.spi.SessionFactoryOptions` are the options ultimately passed to the `SessionFactory` being
built. They represent the choices applied by the user via the `SessionFactoryBuilder` contract. Custom integrations
can leverage this and the `SessionFactoryBuilder` to also expose custom option setting.
[[example1]]
.Custom SessionFactoryBuilderFactory with additional option
====
[source, JAVA]
----
public class CustomSessionFactoryBuilderFactory
implements SessionFactoryBuilderFactory {
@Override
public SessionFactoryBuilder getSessionFactoryBuilder(
MetadataImplementor metadata,
SessionFactoryBuilderImplementor defaultBuilder) {
return new CustomSessionFactoryBuilder( metadata, defaultBuilder );
}
}
public class CustomSessionFactoryBuilder
extends AbstractDelegatingSessionFactoryBuilder {
private final MetadataImplementor metadata;
private final boolean customSetting;
public DelegatingSessionFactoryBuilder(
MetadataImplementor metadata,
SessionFactoryBuilderImplementor delegate) {
super( delegate );
this.metadata = metadata;
// initialize customSetting, maybe based on config settings...
ConfigurationService cfgService = metadata.getMetadataBuildingOptions()
.getServiceRegistry()
.getService( ConfigurationService.class );
this.customSetting = cfgService.getSetting(
"com.acme.domain.custom_setting",
StandardConverters.BOOLEAN,
true
);
}
@Override
public DelegatingSessionFactoryBuilder unwrap() {
return (DelegatingSessionFactoryBuilder) this;
}
public CustomSessionFactoryBuilder applyCustomSetting(boolean enabled) {
this.customSetting = enabled;
return this;
}
@Override
public SessionFactory build() {
CustomSessionFactoryOptions options = new CustomSessionFactoryOptions(
getDelegate().buildSessionFactoryOptions(),
customSetting
);
return new CustomSessionFactory( metadata, options );
}
}
public class CustomSessionFactoryOptions
extends AbstractDelegatingSessionFactoryOptions {
private final boolean customSetting;
public CustomSessionFactoryOptions(
SessionFactoryOptions baseOptions,
boolean customSetting) {
super( baseOptions );
this.customSetting = customSetting;
}
public boolean getCustomSetting() {
return customSetting;
}
}
----
====
Users can then build your custom `SessionFactory` still using the normal Hibernate bootstrap. In fact,
accepting defaults for your custom settings/options, their code does not even change. Of course they
can also apply selections to your custom settings/options as well:
[[example2]]
.Example usage
====
[source, JAVA]
----
Metadata metadata = ...;
// The SessionFactory returned here is concretely
// a CustomSessionFactory
SessionFactory sf = metadata.getSessionFactoryBuilder()
.unwrap( CustomSessionFactoryBuilder.class )
.applyCustomSetting( false )
.buildSessionFactory();
----
====

View File

@ -1,18 +0,0 @@
[[wildfly-guide]]
= Using latest Hibernate ORM within WildFly
== Hibernate ORM within WildFly
The https://wildfly.org/[WildFly application server] includes Hibernate ORM as the default Jakarta Persistence provider out of the box.
In previous versions of Hibernate ORM, we offered a "feature pack" to enable anyone to use the very latest version in
WildFly as soon as a new release of Hibernate ORM was published.
Unfortunately, since version 5.5 is upgrading to Jakarta Persistence 3.0 and targets integration with components of the Jakarta
EE 9 stack, such feature had to be disabled.
As soon as WildFly releases a Jakarta EE 9 compatible server it might be possible to re-introduce such a feature, but
we can't guarantee that we will do this as the server changed the tooling to define such packs.
As usual, please let us know how important this is for you, and while we'll gladly help to make this happen we might need
to rely on volunteers to help by contributing patches, testing it out and providing feedback.

View File

@ -62,7 +62,8 @@ It was done here only for completeness of an example.
The `Person_.name` reference is an example of the static form of Jakarta Persistence Metamodel reference.
We will use that form exclusively in this chapter.
See the documentation for the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/topical/html_single/metamodelgen/MetamodelGenerator.html[Hibernate Jakarta Persistence Metamodel Generator] for additional details on the Jakarta Persistence static Metamodel.
See <<tooling>> for details on generating this static metamodel.
====
[[criteria-typedquery-expression]]

View File

@ -1,90 +1,25 @@
[[tooling]]
== Build Tool Integration
:rootProjectDir: ../../../../../../..
:documentationProjectDir: {rootProjectDir}/documentation
:documentationModel: {documentationProjectDir}/src/main/java/org/hibernate/userguide/model
Hibernate provides a few build-time services available as plugins for
https://gradle.org[Gradle], https://maven.org[Maven] and https://ant.org[Ant].
Hibernate provides build-time services available as plugins for
These services include -
* <<tooling-gradle,Gradle>>
* <<tooling-maven,Maven>>
* <<tooling-ant,Ant>>
* Bytecode enhancement
* Schema management
* Static Metamodel generation
These services include
* <<tooling-enhancement,Bytecode enhancement>>
* <<tooling-modelgen,Static Metamodel generation>>
* <<tooling-schema,Schema management>>
[[tooling-enhancement]]
=== Bytecode Enhancement
include::enhancement.adoc[]
include::modelgen.adoc[]
include::schema.adoc[]
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
include::gradle.adoc[]
include::maven.adoc[]
include::ant.adoc[]

View File

@ -0,0 +1,36 @@
[[tooling-ant]]
=== Ant Plugin
Hibernate provides https://ant.apache.org/[Ant] support ...
[[tooling-ant-modelgen]]
==== Static Metamodel Generation in Ant
As mentioned in <<tooling-modelgen>>, the generator is implemented as an
annotation processor and can be used anywhere javac is used - such as
Ant's https://ant.apache.org/manual/Tasks/javac.html[javac] task.
[[javac-task-example]]
.Javac task configuration
====
[source, XML]
----
<javac srcdir="${src.dir}"
destdir="${target.dir}"
failonerror="false"
fork="true"
classpath="${classpath}">
<compilerarg value="-processorpath" />
<compilerarg value="/path/to/metamodel-generator.jar"/>
<compilerarg value="-proc:only"/>
</javac>
----
====
[[tooling-ant-schema]]
==== Schema Management
Coming soon

View File

@ -0,0 +1,27 @@
[[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.

View File

@ -1,23 +0,0 @@
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

@ -0,0 +1,113 @@
[[tooling-gradle]]
=== Gradle Plugin
For integrating with https://gradle.org[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.
To apply the plugin, use Gradle's `plugins {}` block:
[source,gradle]
----
plugins {
id "org.hibernate.orm" version "<version-to-use>"
}
----
Applying the plugin creates a `hibernate` extension (`HibernateOrmSpec`) to configure the plugin.
By default, when the plugin is applied, support for both bytecode enhancement and static metamodel
generation is enabled.
[source,gradle]
----
hibernate {
// for illustration, let's disable both
disableEnhancement
disableJpaMetamodel
}
----
[[tooling-gradle-enhancement]]
==== Bytecode Enhancement
Enhancement is configured through the `enhancement` extension:
[source,gradle]
----
hibernate {
enhancement {
// for illustration, enable them all
lazyInitialization true
dirtyTracking true
associationManagement true
}
}
----
The extension is of type `EnhancementSpec` which exposes the following properties:
enableLazyInitialization:: Whether to incorporate lazy loading support into the enhanced bytecode
enableDirtyTracking:: Whether to incorporate dirty tracking into the enhanced bytecode
enableAssociationManagement:: Whether to add bidirectional association management into the enhanced bytecode
Which all default to false (disabled).
It also exposes the following method forms:
* lazyInitialization(boolean)
* dirtyTracking(boolean)
* associationManagement(boolean)
[[tooling-gradle-modelgen]]
==== Static Metamodel Generation
One approach to integrate Static Metamodel generation into a Gradle build is to
use Gradle's support for annotation processors -
[source,gradle]
----
dependencies {
annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateVersion}"
}
----
When the build does not need bytecode enhancement support, this is a perfectly valid solution.
The plugin supports simpler configuration of the generator using the registered
`jpaMetamodel` extension:
[source,gradle]
----
hibernate {
jpaMetamodel {
applyGeneratedAnnotation false
suppress 'raw'
generationOutputDirectory "${buildDir}/generated/sources/modelgen"
compileOutputDirectory "${buildDir}/classes/java/modelgen"
}
}
----
The extension is of type `JpaMetamodelGenerationSpec`, which exposes the following configuration properties:
applyGeneratedAnnotation:: Should the `javax.annotation.processing.Generated` annotation be added to the
generated classes. Defaults to `true`.
suppressions:: Suppressions to add to the generated classes. Defaults to `['raw', 'deprecation']`
generationOutputDirectory:: Directory where the generated metamodel classes should be created. Defaults
to `${buildDir}/generated/sources/jpaMetamodel`
[[tooling-gradle-modelgen-compile-output]]
compileOutputDirectory:: Directory where the classes compiled from the generated metamodel classes should be
created. Defaults to `${buildDir}/classes/java/jpaMetamodel`.
It also exposes the following method forms:
* applyGeneratedAnnotation(boolean)
* suppress(String)
* generationOutputDirectory(Object)
* compileOutputDirectory(Object)

View File

@ -0,0 +1,16 @@
[[tooling-maven]]
=== Maven Plugin
Hibernate provides a https://maven.apache.org/[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 <<tooling-gradle>> for details
on the configuration settings. By default, all enhancements are disabled.
.Apply the Maven plugin
====
[source,xml]
----
include::extras/maven-example.pom[]
----
====

View File

@ -0,0 +1,109 @@
[[tooling-modelgen]]
=== Static Metamodel Generator
:rootProjectDir: ../../../../../../..
:documentationProjectDir: {rootProjectDir}/documentation
:documentationModel: {documentationProjectDir}/src/main/java/org/hibernate/userguide/model
:documentationMetamodel: {documentationProjectDir}/target/generated/sources/annotationProcessor/java/main/org/hibernate/userguide/model
:toolingTestsDir: {documentationProjectDir}/src/test/java/org/hibernate/userguide/tooling
Jakarta Persistence defines a typesafe Criteria API which allows `Criteria` queries to be constructed in a
strongly-typed manner, utilizing so-called static metamodel classes. For developers, it is important that
the task of the metamodel generation can be automated. Hibernate Static Metamodel Generator is an annotation
processor based on https://jcp.org/en/jsr/detail?id=269[JSR_269] with the task of creating Jakarta Persistence
static metamodel classes.
See <<criteria>> for discussion of Jakarta Persistence criteria queries.
The Hibernate Static Metamodel Generator is defined by the published `org.hibernate.orm:metamodel-generator`
artifact. As it is defined as an
https://docs.oracle.com/en/java/javase/11/tools/javac.html#GUID-082C33A5-CBCA-471A-845E-E77F79B7B049[annotation processor],
it is usable anytime `javac` is used. See the tool-specific discussions (<<tooling-gradle,Gradle>>, <<tooling-maven,Maven>>
and <<tooling-ant,Ant>>) for details on integrating the generator into those environments.
NOTE:: The fully qualified name of the processor class is `org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor`.
[TIP]
====
The `javac` option _-proc:only_ instructs the compiler to just run the annotation processing.
You can also disable annotation processing by specifying _-proc:none_.
Run `'javac -help'` to see which other annotation processor relevant options can be specified.
====
The structure of the metamodel classes is described in the Jakarta Persistence
specification, but for completeness the definition is repeated in the following
paragraphs. For every class in a persistence-unit, the generator will produce
a static metamodel class based on the following rules:
* For each managed class `X` in package `p`, a metamodel class `X_` is created in package `p`.
* The name of the metamodel class is derived from the name of the managed class by appending "_" to the managed class name.
* The metamodel class `X_` must be annotated with the `jakarta.persistence.StaticMetamodel` annotation. The generation
can also be configured to add the `javax.annotation.processing.Generated` annotation.
* If class `X` extends another class `S`, where `S` is the most derived managed class extended by `X`, then
class `X_` must extend class `S_`, where `S_` is the metamodel class created for `S`.
* For every persistent singular attribute `y` declared by class `X`, where the type of `y` is `Y`,
the metamodel class must contain a declaration as follows:
public static volatile SingularAttribute<X, Y> y;
* For every persistent plural attribute `z` declared by class `X`, where the element type of `z` is `Z`, the metamodel
class must contain a declaration as follows:
** if the collection type of `z` is `java.util.Collection`, then
public static volatile CollectionAttribute<X, Z> z;
** if the collection type of `z` is `java.util.Set`, then
public static volatile SetAttribute<X, Z> z;
** if the collection type of `z` is `java.util.List`, then
public static volatile ListAttribute<X, Z> z;
** if the collection type of `z` is `java.util.Map`, then
+
public static volatile MapAttribute<X, K, Z> z;
+
where `K` is the type of the key of the map in class `X`
* Import statements must be included for `jakarta.persistence.metamodel` types as
needed, as well as all domain model classes (i.e., `X`, `S`, `Y`, `Z`, and `K`).
As an example, consider the following domain model -
[[ex-tooling-modelgen-model]]
.`Order` and `Item` entities
====
[source, JAVA, indent=0]
----
include::{documentationModel}/tooling/Customer.java[tags=tooling-modelgen-model]
include::{documentationModel}/tooling/Order.java[tags=tooling-modelgen-model]
include::{documentationModel}/tooling/Item.java[tags=tooling-modelgen-model]
----
====
Given this model, the generator will produce classes named `Customer_`, `Order_` and `Item_`. As an example:
[[tooling-modelgen-metamodel]]
.`Order_`
====
[source, JAVA, indent=0]
----
include::{documentationMetamodel}/tooling/Order_.java[]
----
====
At boot-time, Hibernate will find these classes and populate them. They can then be used in
Criteria queries for type-safe path references. For example:
[[tooling-modelgen-usage]]
.Static Metamodel usage
====
[source, JAVA, indent=0]
----
include::{toolingTestsDir}/modelgen/ModelGenTests.java[tags=tooling-modelgen-usage]
----
====

View File

@ -0,0 +1,4 @@
[[tooling-schema]]
=== Schema Management
Coming soon

View File

@ -0,0 +1,39 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.model.tooling;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import jakarta.persistence.Id;
import jakarta.persistence.Basic;
/**
* @author Steve Ebersole
*/
@Table(name = "customers")
//tag::tooling-modelgen-model[]
@Entity
public class Customer {
@Id
private Integer id;
@Basic
private String name;
// getters and setters omitted for brevity
//end::tooling-modelgen-model[]
private Customer() {
// for Hibernate use
}
public Customer(Integer id, String name) {
this.id = id;
this.name = name;
}
//tag::tooling-modelgen-model[]
}
//end::tooling-modelgen-model[]

View File

@ -0,0 +1,45 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.model.tooling;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
/**
* @author Steve Ebersole
*/
@Table(name = "items")
//tag::tooling-modelgen-model[]
@Entity
public class Item {
@Id
Integer id;
int quantity;
@ManyToOne
Order order;
// getters and setters omitted for brevity
//end::tooling-modelgen-model[]
public Item() {
}
public Item(Integer id, int quantity, Order order) {
this.id = id;
this.quantity = quantity;
this.order = order;
order.items.add( this );
}
//tag::tooling-modelgen-model[]
}
//end::tooling-modelgen-model[]

View File

@ -0,0 +1,49 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.model.tooling;
import java.math.BigDecimal;
import java.util.Set;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
/**
* @author Steve Ebersole
*/
//tag::tooling-modelgen-model[]
@Entity
@Table(name = "orders")
public class Order {
@Id
Integer id;
@ManyToOne
Customer customer;
@OneToMany
Set<Item> items;
BigDecimal totalCost;
// standard setter/getter methods
//end::tooling-modelgen-model[]
public Order() {
}
public Order(Integer id, Customer customer, BigDecimal totalCost) {
this.id = id;
this.customer = customer;
this.totalCost = totalCost;
}
//tag::tooling-modelgen-model[]
}
//end::tooling-modelgen-model[]

View File

@ -0,0 +1,44 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.userguide.tooling.modelgen;
import java.math.BigDecimal;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import org.hibernate.userguide.model.tooling.Customer;
import org.hibernate.userguide.model.tooling.Item;
import org.hibernate.userguide.model.tooling.Order;
import org.hibernate.userguide.model.tooling.Order_;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
/**
* @author Steve Ebersole
*/
@DomainModel( annotatedClasses = { Order.class, Item.class, Customer.class } )
@SessionFactory
public class ModelGenTests {
@Test
public void testIt(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
//tag::tooling-modelgen-usage[]
final CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
final CriteriaQuery<Customer> criteria = criteriaBuilder.createQuery( Customer.class );
final Root<Order> root = criteria.from( Order.class );
criteria.select( root.get( Order_.customer ) );
criteria.where( criteriaBuilder.greaterThan( root.get( Order_.totalCost ), new BigDecimal( 100 ) ) );
//end::tooling-modelgen-usage[]
} );
}
}

View File

@ -77,6 +77,10 @@ public class JpaMetamodelGenerationSpec {
return applyGeneratedAnnotation;
}
public void applyGeneratedAnnotation(boolean apply) {
applyGeneratedAnnotation.set( apply );
}
public SetProperty<String> getSuppressions() {
return suppressions;
}

View File

@ -300,6 +300,7 @@ public class JpaMetamodelGenerationTask extends DefaultTask {
public static void apply(HibernateOrmSpec ormDsl, SourceSet mainSourceSet, Project project) {
final String mainCompileTaskName = mainSourceSet.getCompileJavaTaskName();
final JavaCompile mainCompileTask = (JavaCompile) project.getTasks().getByName( mainCompileTaskName );
final Task compileResourcesTask = project.getTasks().getByName( "processResources" );
final JpaMetamodelGenerationTask genTask = project.getTasks().create(
DSL_NAME,
@ -313,8 +314,6 @@ public class JpaMetamodelGenerationTask extends DefaultTask {
genTask.setDescription( "Generates the JPA 'static metamodel'" );
genTask.dependsOn( mainCompileTask );
final Task compileResourcesTask = project.getTasks().getByName( "processResources" );
genTask.dependsOn( compileResourcesTask );
final JavaCompile compileJpaMetamodelTask = project.getTasks().create( COMPILE_DSL_NAME, JavaCompile.class );
@ -323,6 +322,7 @@ public class JpaMetamodelGenerationTask extends DefaultTask {
compileJpaMetamodelTask.setSourceCompatibility( mainCompileTask.getSourceCompatibility() );
compileJpaMetamodelTask.setTargetCompatibility( mainCompileTask.getTargetCompatibility() );
genTask.finalizedBy( compileJpaMetamodelTask );
mainCompileTask.finalizedBy( compileJpaMetamodelTask );
compileJpaMetamodelTask.dependsOn( genTask );
compileJpaMetamodelTask.source( project.files( ormDsl.getJpaMetamodelSpec().getGenerationOutputDirectory() ) );
compileJpaMetamodelTask.getDestinationDirectory().set( ormDsl.getJpaMetamodelSpec().getCompileOutputDirectory() );