ORM + Gradle
HHH-14285 - project template HHH-14286 - Gradle plugin
This commit is contained in:
parent
4d8c89920a
commit
29848c49db
|
@ -14,7 +14,7 @@ before_script:
|
|||
- java -version
|
||||
- ./gradlew assemble
|
||||
script:
|
||||
- ./gradlew check -Plog-test-progress=true
|
||||
- ./gradlew check -Plog-test-progress=true --stacktrace
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/
|
||||
|
|
|
@ -10,6 +10,7 @@ buildscript {
|
|||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'org.hibernate.build.gradle:hibernate-matrix-testing:3.0.0.Final'
|
||||
classpath 'org.hibernate.build.gradle:version-injection-plugin:1.0.0'
|
||||
|
|
|
@ -12,6 +12,8 @@ ext {
|
|||
projectsToSkipWhenAggregatingJavadocs = [
|
||||
'documentation',
|
||||
'hibernate-entitymanager',
|
||||
'hibernate-gradle-plugin',
|
||||
'project-template',
|
||||
'hibernate-infinispan',
|
||||
'hibernate-ehcache',
|
||||
'hibernate-java8',
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// make sure Java plugin is applied
|
||||
apply plugin : 'java'
|
||||
|
||||
apply from: rootProject.file( 'gradle/base-information.gradle' )
|
||||
|
||||
javadoc {
|
||||
exclude( "**/internal/*" )
|
||||
exclude( "**/generated-src/**" )
|
||||
|
||||
final int currentYear = new GregorianCalendar().get( Calendar.YEAR )
|
||||
|
||||
configure( options ) {
|
||||
// this is the config needed to use asciidoclet for Javadoc rendering. It relies on a build from John's PR @ https://github.com/asciidoctor/asciidoclet/pull/91
|
||||
// however, the PR does not work for me in that Javadocs with `@asciidoclet` are not rendered using asciidoc(tor/let). Also tried the preferable `@asciidoc`
|
||||
// with the same result. Leaving all this config in place however as the outcome is the same as not enabling it.
|
||||
// todo (6.0) : need to find out why the asciidoclet PR does not work
|
||||
//
|
||||
// Travis CI JDK 11 build did not like this
|
||||
// docletpath = configurations.asciidoclet.files.asType(List)
|
||||
// doclet = 'org.asciidoctor.Asciidoclet'
|
||||
windowTitle = "$project.name JavaDocs"
|
||||
docTitle = "$project.name JavaDocs ($project.version)"
|
||||
bottom = "Copyright © 2001-$currentYear <a href=\"http://redhat.com\">Red Hat, Inc.</a> All Rights Reserved."
|
||||
use = true
|
||||
encoding = 'UTF-8'
|
||||
links += [
|
||||
'https://docs.oracle.com/javase/8/docs/api/',
|
||||
'http://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/',
|
||||
'http://docs.jboss.org/cdi/api/2.0/',
|
||||
'https://javaee.github.io/javaee-spec/javadocs/'
|
||||
]
|
||||
tags = [ "apiNote", 'implSpec', 'implNote', 'todo' ]
|
||||
|
||||
if ( JavaVersion.current().isJava11Compatible() ) {
|
||||
//The need to set `--source 1.8` applies to all JVMs after 11, and also to 11
|
||||
// but after excluding the first two builds; see also specific comments on
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8212233?focusedCommentId=14245762
|
||||
// For now, let's be compatible with JDK 11.0.3+. We can improve on it if people
|
||||
// complain they cannot build with JDK 11.0.0, 11.0.1 and 11.0.2.
|
||||
System.out.println("Forcing Javadoc in Java 8 compatible mode");
|
||||
options.source = project.baselineJavaVersion
|
||||
}
|
||||
|
||||
addStringOption( 'Xdoclint:none', '-quiet' )
|
||||
|
||||
tags(
|
||||
'todo:X"',
|
||||
'apiNote:a:"API Note:"',
|
||||
'implSpec:a:"Implementation Specification:"',
|
||||
'implNote:a:"Implementation Note:"'
|
||||
)
|
||||
}
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
ext {
|
||||
|
||||
junitVersion = '4.12'
|
||||
junitVintageVersion = '5.3.1'
|
||||
junit5Version = '5.3.1'
|
||||
junitVintageVersion = '5.4.2'
|
||||
junit5Version = '5.4.2'
|
||||
|
||||
h2Version = '1.4.199'
|
||||
bytemanVersion = '4.0.13' //Compatible with JDK16
|
||||
|
|
|
@ -117,61 +117,9 @@ task javadocJar(type: Jar) {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Javadoc
|
||||
|
||||
apply from: rootProject.file( 'gradle/javadoc.gradle' )
|
||||
|
||||
javadoc {
|
||||
exclude( "**/internal/*" )
|
||||
exclude( "**/generated-src/**" )
|
||||
|
||||
final int currentYear = new GregorianCalendar().get( Calendar.YEAR )
|
||||
|
||||
configure( options ) {
|
||||
// this is the config needed to use asciidoclet for Javadoc rendering. It relies on a build from John's PR @ https://github.com/asciidoctor/asciidoclet/pull/91
|
||||
// however, the PR does not work for me in that Javadocs with `@asciidoclet` are not rendered using asciidoc(tor/let). Also tried the preferable `@asciidoc`
|
||||
// with the same result. Leaving all this config in place however as the outcome is the same as not enabling it.
|
||||
// todo (6.0) : need to find out why the asciidoclet PR does not work
|
||||
//
|
||||
// Travis CI JDK 11 build did not like this
|
||||
// docletpath = configurations.asciidoclet.files.asType(List)
|
||||
// doclet = 'org.asciidoctor.Asciidoclet'
|
||||
windowTitle = "$project.name JavaDocs"
|
||||
docTitle = "$project.name JavaDocs ($project.version)"
|
||||
bottom = "Copyright © 2001-$currentYear <a href=\"http://redhat.com\">Red Hat, Inc.</a> All Rights Reserved."
|
||||
use = true
|
||||
encoding = 'UTF-8'
|
||||
links += [
|
||||
'https://docs.oracle.com/javase/8/docs/api/',
|
||||
'http://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/',
|
||||
'http://docs.jboss.org/cdi/api/2.0/',
|
||||
'https://javaee.github.io/javaee-spec/javadocs/'
|
||||
]
|
||||
tags = [ "apiNote", 'implSpec', 'implNote', 'todo' ]
|
||||
|
||||
if ( JavaVersion.current().isJava11Compatible() ) {
|
||||
//The need to set `--source 1.8` applies to all JVMs after 11, and also to 11
|
||||
// but after excluding the first two builds; see also specific comments on
|
||||
// https://bugs.openjdk.java.net/browse/JDK-8212233?focusedCommentId=14245762
|
||||
// For now, let's be compatible with JDK 11.0.3+. We can improve on it if people
|
||||
// complain they cannot build with JDK 11.0.0, 11.0.1 and 11.0.2.
|
||||
System.out.println("Forcing Javadoc in Java 8 compatible mode");
|
||||
options.source = project.baselineJavaVersion
|
||||
}
|
||||
|
||||
if ( JavaVersion.current().isJava8Compatible() ) {
|
||||
addStringOption( 'Xdoclint:none', '-quiet' )
|
||||
}
|
||||
|
||||
// // by default, exclude the files from Asciidoclet processing
|
||||
// // add the @asciidoclet tag to enable Asciidoclet on a particular file
|
||||
// options.addStringOption( '-exclude-asciidoclet-process', '**' )
|
||||
|
||||
tags(
|
||||
'todo:X"',
|
||||
'apiNote:a:"API Note:"',
|
||||
'implSpec:a:"Implementation Specification:"',
|
||||
'implNote:a:"Implementation Note:"'
|
||||
)
|
||||
}
|
||||
options.addStringOption( 'Xdoclint:none', '-quiet' )
|
||||
|
||||
doFirst {
|
||||
// ordering problems if we try to do this during config phase :(
|
||||
classpath += project.sourceSets.main.output.classesDirs + project.sourceSets.main.compileClasspath + project.configurations.provided
|
||||
|
|
|
@ -194,8 +194,7 @@ abstract class AggregatedServiceLoader<S> {
|
|||
Set<S> result = new LinkedHashSet<>();
|
||||
|
||||
// Always try the aggregated class loader first
|
||||
Iterator<? extends Supplier<S>> providerIterator = providerStream( aggregatedClassLoaderServiceLoader )
|
||||
.iterator();
|
||||
Iterator<? extends Supplier<S>> providerIterator = providerStream( aggregatedClassLoaderServiceLoader ).iterator();
|
||||
while ( providerIterator.hasNext() ) {
|
||||
Supplier<S> provider = providerIterator.next();
|
||||
collectServiceIfNotDuplicate( result, alreadyEncountered, provider );
|
||||
|
|
|
@ -1198,6 +1198,26 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
|||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ManagedResources getManagedResources() {
|
||||
return managedResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by extensions : Hibernate Reactive
|
||||
*/
|
||||
@Override
|
||||
public MetadataImplementor metadata() {
|
||||
if ( this.metadata == null ) {
|
||||
this.metadata = MetadataBuildingProcess.complete(
|
||||
managedResources,
|
||||
metamodelBuilder.getBootstrapContext(),
|
||||
metamodelBuilder.getMetadataBuildingOptions()
|
||||
);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManagerFactoryBuilder withValidatorFactory(Object validatorFactory) {
|
||||
this.validatorFactory = validatorFactory;
|
||||
|
@ -1220,20 +1240,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
|||
// todo : close the bootstrap registry (not critical, but nice to do)
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by extensions : Hibernate Reactive
|
||||
*/
|
||||
protected MetadataImplementor metadata() {
|
||||
if ( this.metadata == null ) {
|
||||
this.metadata = MetadataBuildingProcess.complete(
|
||||
managedResources,
|
||||
metamodelBuilder.getBootstrapContext(),
|
||||
metamodelBuilder.getMetadataBuildingOptions()
|
||||
);
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSchema() {
|
||||
// This seems overkill, but building the SF is necessary to get the Integrators to kick in.
|
||||
|
|
|
@ -9,6 +9,9 @@ package org.hibernate.jpa.boot.spi;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.hibernate.boot.model.process.spi.ManagedResources;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
|
||||
/**
|
||||
* Represents a 2-phase JPA bootstrap process for building a Hibernate EntityManagerFactory.
|
||||
*
|
||||
|
@ -24,6 +27,10 @@ import javax.sql.DataSource;
|
|||
* @author Scott Marlow
|
||||
*/
|
||||
public interface EntityManagerFactoryBuilder {
|
||||
ManagedResources getManagedResources();
|
||||
|
||||
MetadataImplementor metadata();
|
||||
|
||||
/**
|
||||
* Allows passing in a Java EE ValidatorFactory (delayed from constructing the builder, AKA phase 2) to be used
|
||||
* in building the EntityManagerFactory
|
||||
|
@ -32,7 +39,7 @@ public interface EntityManagerFactoryBuilder {
|
|||
*
|
||||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
public EntityManagerFactoryBuilder withValidatorFactory(Object validatorFactory);
|
||||
EntityManagerFactoryBuilder withValidatorFactory(Object validatorFactory);
|
||||
|
||||
/**
|
||||
* Allows passing in a DataSource (delayed from constructing the builder, AKA phase 2) to be used
|
||||
|
@ -42,23 +49,23 @@ public interface EntityManagerFactoryBuilder {
|
|||
*
|
||||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
public EntityManagerFactoryBuilder withDataSource(DataSource dataSource);
|
||||
EntityManagerFactoryBuilder withDataSource(DataSource dataSource);
|
||||
|
||||
/**
|
||||
* Build {@link EntityManagerFactory} instance
|
||||
*
|
||||
* @return The built {@link EntityManagerFactory}
|
||||
*/
|
||||
public EntityManagerFactory build();
|
||||
EntityManagerFactory build();
|
||||
|
||||
/**
|
||||
* Cancel the building processing. This is used to signal the builder to release any resources in the case of
|
||||
* something having gone wrong during the bootstrap process
|
||||
*/
|
||||
public void cancel();
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Perform an explicit schema generation (rather than an "auto" one) based on the
|
||||
*/
|
||||
public void generateSchema();
|
||||
void generateSchema();
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@ public class DependantValue extends SimpleValue implements Resolvable {
|
|||
this.wrappedValue = prototype;
|
||||
}
|
||||
|
||||
public KeyValue getWrappedValue() {
|
||||
return wrappedValue;
|
||||
}
|
||||
|
||||
public Type getType() throws MappingException {
|
||||
return wrappedValue.getType();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,8 @@ ext {
|
|||
idea.module {
|
||||
}
|
||||
|
||||
final File documentationDir = mkdir( "${project.buildDir}/documentation" );
|
||||
final File documentationDir = mkdir( "${project.buildDir}/documentation" )
|
||||
final File projectTemplateStagingDir = mkdir( "${project.buildDir}/projectTemplate" )
|
||||
|
||||
task releaseChecks() {
|
||||
doFirst {
|
||||
|
@ -104,6 +105,12 @@ task assembleDocumentation(type: Task, dependsOn: [rootProject.project( 'documen
|
|||
}
|
||||
}
|
||||
|
||||
task assembleProjectTemplates(type:Copy, dependsOn: project( ":project-template" ).tasks.assembleDist) {
|
||||
def templateProject = project( ":project-template" )
|
||||
from templateProject.layout.buildDirectory.dir( "distributions" )
|
||||
into projectTemplateStagingDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload the documentation to the JBoss doc server
|
||||
*/
|
||||
|
@ -150,9 +157,10 @@ distributions {
|
|||
from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'javassist' }
|
||||
}
|
||||
|
||||
// into( 'lib/jpa' ) {
|
||||
// from parent.project( 'hibernate-entitymanager' ).configurations.archives.allArtifacts.files.filter{ file -> !file.name.endsWith('-sources.jar') }
|
||||
// }
|
||||
into( 'project-template' ) {
|
||||
// todo : hook in some form of variable replacement - especially for version
|
||||
from project( ':project-template' ).files( 'src/main/dist' )
|
||||
}
|
||||
|
||||
// todo (6.0) - add back spatial
|
||||
// into( 'lib/spatial' ) {
|
||||
|
@ -241,11 +249,9 @@ distributions {
|
|||
}
|
||||
}
|
||||
|
||||
distZip.dependsOn assembleDocumentation
|
||||
distTar.dependsOn assembleDocumentation
|
||||
distTar {
|
||||
compression = Compression.GZIP
|
||||
}
|
||||
// this is the common task between distTar and distZip
|
||||
assembleDist.dependsOn assembleDocumentation
|
||||
distTar.compression = Compression.GZIP
|
||||
|
||||
/**
|
||||
* "virtual" task for building both types of dist bundles
|
||||
|
|
|
@ -82,6 +82,9 @@ project(':metamodel-generator').name = 'hibernate-jpamodelgen'
|
|||
include 'hibernate-gradle-plugin'
|
||||
project(':hibernate-gradle-plugin').projectDir = new File(rootProject.projectDir, "tooling/hibernate-gradle-plugin")
|
||||
|
||||
include 'project-template'
|
||||
project(':project-template').projectDir = new File(rootProject.projectDir, "tooling/project-template")
|
||||
|
||||
include 'hibernate-enhance-maven-plugin'
|
||||
project(':hibernate-enhance-maven-plugin').projectDir = new File(rootProject.projectDir, "tooling/hibernate-enhance-maven-plugin")
|
||||
|
||||
|
@ -90,4 +93,4 @@ rootProject.children.each { project ->
|
|||
assert project.projectDir.isDirectory()
|
||||
assert project.buildFile.exists()
|
||||
assert project.buildFile.isFile()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
= Hibernate ORM Gradle Plugin
|
||||
|
||||
A Gradle plugin for introducing Hibernate tasks and capabilities into a build.
|
||||
|
||||
|
||||
== Set up
|
||||
|
||||
```
|
||||
plugins {
|
||||
id 'org.hibernate.orm' version='X'
|
||||
}
|
||||
|
||||
// HibernateOrmSpec
|
||||
hibernate {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
== Bytecode Enhancement
|
||||
|
||||
The plugin can perform build-time enhancement of the domain classes. This is controlled
|
||||
by the `enhancement` portion of the `hibernate` extension:
|
||||
|
||||
```
|
||||
hibernate {
|
||||
// EnhancementSpec
|
||||
enhancement {
|
||||
// available options - all default to false
|
||||
lazyInitialization( true )
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
== DSL
|
||||
|
||||
The `hibernate` DSL extension is the main entry into configuring the plugin
|
||||
|
||||
```
|
||||
hibernate {
|
||||
}
|
||||
```
|
||||
|
||||
At this time, there is no configuration at this level.
|
||||
|
||||
== Capa
|
||||
|
||||
== Tasks
|
||||
|
||||
== Additional Resources
|
||||
|
||||
* https://plugins.gradle.org/plugin/org.hibernate.orm
|
|
@ -1,6 +0,0 @@
|
|||
Defines a Gradle plugin for introducing Hibernate specific tasks and capabilities into and end-user build.
|
||||
|
||||
Currently the only capability added is for bytecode enhancement of the user domain model, although other capabilities are
|
||||
planned.
|
||||
|
||||
todo : usage
|
|
@ -1,29 +1,121 @@
|
|||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
apply plugin: 'groovy'
|
||||
|
||||
description = "Gradle plugin for integrating Hibernate functionality into your build"
|
||||
plugins {
|
||||
id 'java-gradle-plugin'
|
||||
id 'com.github.sebersole.testkit-junit5' version '0.9.5'
|
||||
|
||||
apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'maven'
|
||||
// for portal publishing
|
||||
id "com.gradle.plugin-publish" version "0.12.0"
|
||||
id "nu.studer.credentials" version "2.1"
|
||||
|
||||
// for publishing snapshots
|
||||
id 'maven-publish'
|
||||
id 'org.hibernate.build.maven-repo-auth'
|
||||
|
||||
id 'idea'
|
||||
id 'eclipse'
|
||||
}
|
||||
|
||||
description = "Gradle plugin for integrating Hibernate aspects into your build"
|
||||
|
||||
apply from: rootProject.file( 'gradle/base-information.gradle' )
|
||||
apply from: rootProject.file( 'gradle/libraries.gradle' )
|
||||
apply from: rootProject.file( 'gradle/javadoc.gradle' )
|
||||
|
||||
ext {
|
||||
pluginId = 'org.hibernate.orm'
|
||||
pluginVersion = project.version
|
||||
|
||||
//noinspection GrUnresolvedAccess
|
||||
publishKey = credentials.'hibernate.gradle.publish.key'
|
||||
//noinspection GrUnresolvedAccess
|
||||
publishSecret = credentials.'hibernate.gradle.publish.secret'
|
||||
|
||||
if ( publishKey != null && publishSecret != null ) {
|
||||
project.'gradle.publish.key' = publishKey
|
||||
project.'gradle.publish.secret' = publishSecret
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile( project( ':hibernate-core' ) )
|
||||
compile( libraries.jpa )
|
||||
compile( libraries.javassist )
|
||||
compile( libraries.byteBuddy )
|
||||
compile gradleApi()
|
||||
compile localGroovy()
|
||||
implementation( project( ':hibernate-core' ) )
|
||||
implementation project( ':hibernate-testing' )
|
||||
implementation( libraries.jpa )
|
||||
implementation( libraries.javassist )
|
||||
implementation( libraries.byteBuddy )
|
||||
}
|
||||
|
||||
tasks.withType( GroovyCompile ) {
|
||||
options.encoding = 'UTF-8'
|
||||
sourceCompatibility = project.baselineJavaVersion
|
||||
targetCompatibility = project.baselineJavaVersion
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
ormPlugin {
|
||||
id = project.pluginId
|
||||
implementationClass = 'org.hibernate.orm.tooling.gradle.HibernateOrmPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pluginBundle {
|
||||
website = 'https://github.com/hibernate/hibernate-orm/tree/master/tooling/hibernate-gradle-plugin'
|
||||
vcsUrl = 'https://github.com/hibernate/hibernate-orm/tree/master/tooling/hibernate-gradle-plugin'
|
||||
tags = ['hibernate','orm','bytecode','enhancement','bytebuddy']
|
||||
|
||||
plugins {
|
||||
ormPlugin {
|
||||
id = project.pluginId
|
||||
displayName = 'Gradle plugin for Hibernate ORM'
|
||||
description = 'Applies Hibernate aspects into the build'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
filter( ReplaceTokens, tokens: [ 'hibernateVersion': getVersion() ] )
|
||||
}
|
||||
|
||||
|
||||
task release
|
||||
|
||||
if ( project.version.toString().endsWith( '-SNAPSHOT' ) ) {
|
||||
tasks.publishPlugins.enabled = false
|
||||
tasks.release.dependsOn tasks.publish
|
||||
}
|
||||
else {
|
||||
tasks.publish.enabled = false
|
||||
tasks.release.dependsOn( tasks.publishPlugins )
|
||||
}
|
||||
|
||||
tasks.publishPlugins {
|
||||
doFirst {
|
||||
if ( project.'gradle.publish.key' == null ) {
|
||||
throw new RuntimeException( "`gradle.publish.key` not found" )
|
||||
}
|
||||
if ( project.'gradle.publish.secret' == null ) {
|
||||
throw new RuntimeException( "`gradle.publish.secret` not found" )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// for SNAPSHOT version
|
||||
publishing {
|
||||
publications {
|
||||
plugin( MavenPublication ) {
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name 'jboss-snapshots-repository'
|
||||
url 'https://repository.jboss.org/nexus/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle
|
||||
|
||||
/**
|
||||
* Gradle DSL extension for configuring various Hibernate bytecode enhancement. Registered
|
||||
* under "hibernate.enhance".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class EnhanceExtension implements Serializable {
|
||||
def boolean enableLazyInitialization = false
|
||||
def boolean enableDirtyTracking = false
|
||||
def boolean enableAssociationManagement = false
|
||||
def boolean enableExtendedEnhancement = false
|
||||
|
||||
boolean shouldApply() {
|
||||
return enableLazyInitialization || enableDirtyTracking || enableAssociationManagement || enableExtendedEnhancement;
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.util.ConfigureUtil
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class EnhanceTask extends DefaultTask {
|
||||
@Input
|
||||
EnhanceExtension options
|
||||
@InputFiles
|
||||
SourceSet[] sourceSets
|
||||
|
||||
@TaskAction
|
||||
void enhance() {
|
||||
for ( SourceSet sourceSet: sourceSets ) {
|
||||
EnhancementHelper.enhance( sourceSet, options, project )
|
||||
}
|
||||
}
|
||||
|
||||
void options(Closure closure) {
|
||||
options = new EnhanceExtension()
|
||||
ConfigureUtil.configure( closure, options )
|
||||
}
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnhancementHelper {
|
||||
static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) {
|
||||
final ClassLoader classLoader = toClassLoader( sourceSet.getRuntimeClasspath() );
|
||||
|
||||
final EnhancementContext enhancementContext = new DefaultEnhancementContext() {
|
||||
@Override
|
||||
public ClassLoader getLoadingClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return options.getEnableAssociationManagement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return options.getEnableDirtyTracking();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return options.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadable(UnloadedField field) {
|
||||
return options.getEnableLazyInitialization();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return options.getEnableExtendedEnhancement();
|
||||
}
|
||||
};
|
||||
|
||||
if ( options.getEnableExtendedEnhancement() ) {
|
||||
project.getLogger().warn("Extended enhancement is enabled. Classes other than entities may be modified. You should consider access the entities using getter/setter methods and disable this property. Use at your own risk." );
|
||||
}
|
||||
|
||||
final Enhancer enhancer = Environment.getBytecodeProvider().getEnhancer( enhancementContext );
|
||||
|
||||
for ( File classesDir: sourceSet.getOutput().getClassesDirs() ) {
|
||||
final FileTree fileTree = project.fileTree( classesDir );
|
||||
for ( File file : fileTree ) {
|
||||
if ( !file.getName().endsWith( ".class" ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final byte[] enhancedBytecode = doEnhancement( classesDir, file, enhancer );
|
||||
if ( enhancedBytecode != null ) {
|
||||
writeOutEnhancedClass( enhancedBytecode, file, project.getLogger() );
|
||||
project.getLogger().info( "Successfully enhanced class [" + file + "]" );
|
||||
}
|
||||
else {
|
||||
project.getLogger().info( "Skipping class [" + file.getAbsolutePath() + "], not an entity nor embeddable" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ClassLoader toClassLoader(FileCollection runtimeClasspath) {
|
||||
List<URL> urls = new ArrayList<>();
|
||||
for ( File file : runtimeClasspath ) {
|
||||
try {
|
||||
urls.add( file.toURI().toURL() );
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
return new URLClassLoader( urls.toArray( new URL[0] ), Enhancer.class.getClassLoader() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
static byte[] doEnhancement(File root, File javaClassFile, Enhancer enhancer) {
|
||||
try {
|
||||
final String className = determineClassName( root, javaClassFile );
|
||||
final ByteArrayOutputStream originalBytes = new ByteArrayOutputStream();
|
||||
try (final FileInputStream fileInputStream = new FileInputStream( javaClassFile )) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ( ( length = fileInputStream.read( buffer ) ) != -1 ) {
|
||||
originalBytes.write( buffer, 0, length );
|
||||
}
|
||||
}
|
||||
return enhancer.enhance( className, originalBytes.toByteArray() );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new GradleException( "Unable to enhance class : " + javaClassFile, e );
|
||||
}
|
||||
}
|
||||
|
||||
private static String determineClassName(File root, File javaClassFile) {
|
||||
return javaClassFile.getAbsolutePath().substring(
|
||||
root.getAbsolutePath().length() + 1,
|
||||
javaClassFile.getAbsolutePath().length() - ".class".length()
|
||||
).replace( File.separatorChar, '.' );
|
||||
}
|
||||
|
||||
private static void writeOutEnhancedClass(byte[] enhancedBytecode, File file, Logger logger) {
|
||||
try {
|
||||
if ( file.delete() ) {
|
||||
if ( !file.createNewFile() ) {
|
||||
logger.error( "Unable to recreate class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.error( "Unable to delete class file [" + file.getName() + "]" );
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn( "Problem preparing class file for writing out enhancements [" + file.getName() + "]" );
|
||||
}
|
||||
|
||||
try {
|
||||
FileOutputStream outputStream = new FileOutputStream( file, false );
|
||||
try {
|
||||
outputStream.write( enhancedBytecode );
|
||||
outputStream.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Error writing to enhanced class [" + file.getName() + "] to file [" + file.getAbsolutePath() + "]", e );
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
outputStream.close();
|
||||
}
|
||||
catch (IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new GradleException( "Error opening class file for writing : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private EnhancementHelper() {
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.util.ConfigureUtil
|
||||
|
||||
/**
|
||||
* Gradle DSL extension for configuring various Hibernate built-time tasks. Registered
|
||||
* under "hibernate".
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class HibernateExtension {
|
||||
private final Project project
|
||||
|
||||
/**
|
||||
* The source sets that hold persistent model. Default is project.sourceSets.main
|
||||
*/
|
||||
def SourceSet[] sourceSets
|
||||
|
||||
/**
|
||||
* Configuration for bytecode enhancement. Private; see instead {@link #enhance(groovy.lang.Closure)}
|
||||
*/
|
||||
protected EnhanceExtension enhance
|
||||
|
||||
HibernateExtension(Project project) {
|
||||
this.project = project
|
||||
this.sourceSet( project.getConvention().getPlugin( JavaPluginConvention ).sourceSets.main )
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single SourceSet.
|
||||
*
|
||||
* @param sourceSet The SourceSet to add
|
||||
*/
|
||||
void sourceSet(SourceSet sourceSet) {
|
||||
if ( sourceSets == null ) {
|
||||
sourceSets = []
|
||||
}
|
||||
sourceSets += sourceSet
|
||||
}
|
||||
|
||||
void enhance(Closure closure) {
|
||||
enhance = new EnhanceExtension()
|
||||
ConfigureUtil.configure( closure, enhance )
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
|
||||
/**
|
||||
* The Hibernate Gradle plugin. Adds Hibernate build-time capabilities into your Gradle-based build.
|
||||
*
|
||||
* @author Jeremy Whiting
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class HibernatePlugin implements Plugin<Project> {
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().apply( "java" );
|
||||
|
||||
final HibernateExtension hibernateExtension = new HibernateExtension( project );
|
||||
|
||||
project.getLogger().debug( "Adding Hibernate extensions to the build [{}]", project.getName() );
|
||||
project.getExtensions().add( "hibernate", hibernateExtension );
|
||||
|
||||
project.afterEvaluate(
|
||||
p -> applyEnhancement( p, hibernateExtension )
|
||||
);
|
||||
}
|
||||
|
||||
private void applyEnhancement(final Project project, final HibernateExtension hibernateExtension) {
|
||||
if ( hibernateExtension.enhance == null || ! hibernateExtension.enhance.shouldApply() ) {
|
||||
project.getLogger().warn( "Skipping Hibernate bytecode enhancement since no feature is enabled" );
|
||||
return;
|
||||
}
|
||||
|
||||
for ( final SourceSet sourceSet : hibernateExtension.getSourceSets() ) {
|
||||
project.getLogger().debug( "Applying Hibernate enhancement action to SourceSet.{}", sourceSet.getName() );
|
||||
|
||||
final Task compileTask = project.getTasks().findByName( sourceSet.getCompileJavaTaskName() );
|
||||
assert compileTask != null;
|
||||
compileTask.doLast(new EnhancerAction( sourceSet, hibernateExtension, project ));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gradle doesn't allow lambdas in doLast or doFirst configurations and causing up-to-date checks
|
||||
* to fail. Extracting the lambda to an inner class works around this issue.
|
||||
*
|
||||
* @link https://github.com/gradle/gradle/issues/5510
|
||||
*/
|
||||
private static class EnhancerAction implements Action<Task> {
|
||||
|
||||
private final SourceSet sourceSet;
|
||||
|
||||
private final HibernateExtension hibernateExtension;
|
||||
|
||||
private final Project project;
|
||||
|
||||
private EnhancerAction(SourceSet sourceSet, HibernateExtension hibernateExtension, Project project) {
|
||||
this.sourceSet = sourceSet;
|
||||
this.hibernateExtension = hibernateExtension;
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Task task) {
|
||||
EnhancementHelper.enhance( sourceSet, hibernateExtension.enhance, project );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.Directory;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class Helper {
|
||||
|
||||
public static ClassLoader toClassLoader(Directory classesDir) {
|
||||
final File classesDirFile = classesDir.getAsFile();
|
||||
final URI classesDirUri = classesDirFile.toURI();
|
||||
try {
|
||||
final URL url = classesDirUri.toURL();
|
||||
return new URLClassLoader( new URL[] { url }, Enhancer.class.getClassLoader() );
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new GradleException( "Unable to resolve classpath entry to URL : " + classesDirFile.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
|
||||
public static String determineClassName(File root, File javaClassFile) {
|
||||
final Path relativeClassPath = root.toPath().relativize( javaClassFile.toPath() );
|
||||
final String relativeClassPathString = relativeClassPath.toString();
|
||||
final String classNameBase = relativeClassPathString.substring(
|
||||
0,
|
||||
relativeClassPathString.length() - ".class".length()
|
||||
);
|
||||
return classNameBase.replace( File.separatorChar, '.' );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.plugins.JavaPlugin;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.enhance.EnhancementTask;
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.JpaMetamodelGenerationTask;
|
||||
|
||||
/**
|
||||
* Hibernate ORM Gradle plugin
|
||||
*/
|
||||
public class HibernateOrmPlugin implements Plugin<Project> {
|
||||
@Override
|
||||
public void apply(Project project) {
|
||||
project.getPlugins().apply( JavaPlugin.class );
|
||||
|
||||
project.getLogger().debug( "Adding Hibernate extensions to the build [{}]", project.getPath() );
|
||||
final HibernateOrmSpec ormDsl = project.getExtensions().create( HibernateOrmSpec.DSL_NAME, HibernateOrmSpec.class, project );
|
||||
|
||||
final Configuration hibernateOrm = project.getConfigurations().maybeCreate( "hibernateOrm" );
|
||||
project.getDependencies().add(
|
||||
"hibernateOrm",
|
||||
project.provider( () -> "org.hibernate.orm:hibernate-core:" + HibernateVersion.version )
|
||||
);
|
||||
project.getConfigurations().getByName( "implementation" ).extendsFrom( hibernateOrm );
|
||||
|
||||
final JavaPluginConvention javaPluginConvention = project.getConvention().findPlugin( JavaPluginConvention.class );
|
||||
assert javaPluginConvention != null;
|
||||
|
||||
final SourceSetContainer sourceSets = javaPluginConvention.getSourceSets();
|
||||
final SourceSet mainSourceSet = sourceSets.getByName( SourceSet.MAIN_SOURCE_SET_NAME );
|
||||
|
||||
EnhancementTask.apply( ormDsl, mainSourceSet, project );
|
||||
JpaMetamodelGenerationTask.apply( ormDsl, mainSourceSet, project );
|
||||
|
||||
project.getDependencies().add(
|
||||
"implementation",
|
||||
project.provider( () -> "org.hibernate.orm:hibernate-core:" + ormDsl.getHibernateVersionProperty().get() )
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Action;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.ExtensionAware;
|
||||
import org.gradle.api.plugins.ExtensionContainer;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.enhance.EnhancementSpec;
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.JpaMetamodelGenerationSpec;
|
||||
|
||||
/**
|
||||
* Main DSL extension for Hibernate ORM. Available as `project.hibernate`
|
||||
*/
|
||||
public abstract class HibernateOrmSpec implements ExtensionAware {
|
||||
public static final String HIBERNATE = "hibernate";
|
||||
|
||||
public static final String DSL_NAME = HIBERNATE;
|
||||
|
||||
private final Property<String> hibernateVersionProperty;
|
||||
private final Property<Boolean> supportEnhancementProperty;
|
||||
private final Property<Boolean> supportJpaMetamodelProperty;
|
||||
|
||||
private final EnhancementSpec enhancementDsl;
|
||||
private final JpaMetamodelGenerationSpec jpaMetamodelDsl;
|
||||
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public HibernateOrmSpec(Project project) {
|
||||
hibernateVersionProperty = project.getObjects().property( String.class );
|
||||
hibernateVersionProperty.convention( HibernateVersion.version );
|
||||
|
||||
supportEnhancementProperty = project.getObjects().property( Boolean.class );
|
||||
supportEnhancementProperty.convention( true );
|
||||
|
||||
supportJpaMetamodelProperty = project.getObjects().property( Boolean.class );
|
||||
supportJpaMetamodelProperty.convention( true );
|
||||
|
||||
enhancementDsl = getExtensions().create( EnhancementSpec.DSL_NAME, EnhancementSpec.class, this, project );
|
||||
jpaMetamodelDsl = getExtensions().create( JpaMetamodelGenerationSpec.DSL_NAME, JpaMetamodelGenerationSpec.class, this, project );
|
||||
}
|
||||
|
||||
public Property<String> getHibernateVersionProperty() {
|
||||
return hibernateVersionProperty;
|
||||
}
|
||||
|
||||
public void hibernateVersion(String version) {
|
||||
setHibernateVersion( version );
|
||||
}
|
||||
|
||||
public void setHibernateVersion(String version) {
|
||||
hibernateVersionProperty.set( version );
|
||||
}
|
||||
|
||||
public Property<Boolean> getSupportEnhancementProperty() {
|
||||
return supportEnhancementProperty;
|
||||
}
|
||||
|
||||
public void disableEnhancement() {
|
||||
supportEnhancementProperty.set( false );
|
||||
}
|
||||
|
||||
public Property<Boolean> getSupportJpaMetamodelProperty() {
|
||||
return supportJpaMetamodelProperty;
|
||||
}
|
||||
|
||||
public void disableJpaMetamodel() {
|
||||
supportJpaMetamodelProperty.set( false );
|
||||
}
|
||||
|
||||
public EnhancementSpec getEnhancementSpec() {
|
||||
return enhancementDsl;
|
||||
}
|
||||
|
||||
public void enhancement(Action<EnhancementSpec> action) {
|
||||
action.execute( enhancementDsl );
|
||||
}
|
||||
|
||||
public JpaMetamodelGenerationSpec getJpaMetamodelSpec() {
|
||||
return jpaMetamodelDsl;
|
||||
}
|
||||
|
||||
public void jpaMetamodel(Action<JpaMetamodelGenerationSpec>action) {
|
||||
action.execute( jpaMetamodelDsl );
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract ExtensionContainer getExtensions();
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.LineNumberReader;
|
||||
import java.net.URL;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class HibernateVersion {
|
||||
public static volatile String version;
|
||||
|
||||
static {
|
||||
version = determineHibernateVersion();
|
||||
}
|
||||
|
||||
private static String determineHibernateVersion() {
|
||||
final URL versionFileUrl = findVersionFile();
|
||||
try ( final InputStream inputStream = versionFileUrl.openStream() ) {
|
||||
try ( final InputStreamReader inputStreamReader = new InputStreamReader( inputStream ) ) {
|
||||
return new LineNumberReader( inputStreamReader ).readLine();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Unable to read `META-INF/hibernate-orm.version` resource" );
|
||||
}
|
||||
}
|
||||
|
||||
private static URL findVersionFile() {
|
||||
final URL badGunsAndRoses = HibernateOrmSpec.class.getClassLoader().getResource( "META-INF/hibernate-orm.version" );
|
||||
if ( badGunsAndRoses != null ) {
|
||||
return badGunsAndRoses;
|
||||
}
|
||||
|
||||
//noinspection UnnecessaryLocalVariable
|
||||
final URL goodGunsAndRoses = HibernateOrmSpec.class.getClassLoader().getResource( "/META-INF/hibernate-orm.version" );
|
||||
|
||||
return goodGunsAndRoses;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.enhance;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.Directory;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.logging.Logger;
|
||||
import org.gradle.work.InputChanges;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.orm.tooling.gradle.Helper;
|
||||
|
||||
import static org.hibernate.orm.tooling.gradle.Helper.determineClassName;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnhancementHelper {
|
||||
public static void enhance(
|
||||
DirectoryProperty classesDirectoryProperty,
|
||||
InputChanges inputChanges,
|
||||
EnhancementSpec enhancementDsl,
|
||||
Project project) {
|
||||
final Directory classesDir = classesDirectoryProperty.get();
|
||||
final File classesDirFile = classesDir.getAsFile();
|
||||
|
||||
final Enhancer enhancer = generateEnhancer( classesDir, enhancementDsl );
|
||||
|
||||
final String classesDirPath = classesDirFile.getAbsolutePath();
|
||||
|
||||
inputChanges.getFileChanges( classesDirectoryProperty ).forEach(
|
||||
change -> {
|
||||
switch ( change.getChangeType() ) {
|
||||
case ADDED:
|
||||
case MODIFIED: {
|
||||
final File changedFile = change.getFile();
|
||||
if ( changedFile.getName().endsWith( ".class" ) ) {
|
||||
final String classFilePath = changedFile.getAbsolutePath();
|
||||
if ( classFilePath.startsWith( classesDirPath ) ) {
|
||||
// we found the directory it came from
|
||||
// -use that to determine the class name
|
||||
enhance( changedFile, determineClassName( classesDirFile, changedFile ), enhancer, project );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REMOVED: {
|
||||
// nothing to do
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new UnsupportedOperationException( "Unexpected ChangeType : " + change.getChangeType().name() );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private static void enhance(
|
||||
File javaClassFile,
|
||||
String className,
|
||||
Enhancer enhancer,
|
||||
Project project) {
|
||||
final byte[] enhancedBytecode = doEnhancement( javaClassFile, className, enhancer );
|
||||
if ( enhancedBytecode != null ) {
|
||||
writeOutEnhancedClass( enhancedBytecode, javaClassFile, project.getLogger() );
|
||||
project.getLogger().info( "Successfully enhanced class : " + className );
|
||||
}
|
||||
else {
|
||||
project.getLogger().info( "Skipping class : " + className );
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] doEnhancement(File javaClassFile, String className, Enhancer enhancer) {
|
||||
try {
|
||||
return enhancer.enhance( className, Files.readAllBytes( javaClassFile.toPath() ) );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new GradleException( "Unable to enhance class : " + className, e );
|
||||
}
|
||||
}
|
||||
|
||||
private static Enhancer generateEnhancer(Directory classesDir, EnhancementSpec enhancementDsl) {
|
||||
final ClassLoader classLoader = Helper.toClassLoader( classesDir );
|
||||
|
||||
final EnhancementContext enhancementContext = new DefaultEnhancementContext() {
|
||||
@Override
|
||||
public ClassLoader getLoadingClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return enhancementDsl.getEnableAssociationManagement().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return enhancementDsl.getEnableDirtyTracking().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return enhancementDsl.getEnableLazyInitialization().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadable(UnloadedField field) {
|
||||
return enhancementDsl.getEnableLazyInitialization().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return enhancementDsl.getEnableExtendedEnhancement().get();
|
||||
}
|
||||
};
|
||||
|
||||
//noinspection deprecation
|
||||
return Environment.getBytecodeProvider().getEnhancer( enhancementContext );
|
||||
}
|
||||
|
||||
private static void writeOutEnhancedClass(byte[] enhancedBytecode, File file, Logger logger) {
|
||||
try {
|
||||
if ( file.delete() ) {
|
||||
if ( !file.createNewFile() ) {
|
||||
logger.error( "Unable to recreate class file : " + file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.error( "Unable to delete class file : " + file.getAbsolutePath() );
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.warn( "Problem preparing class file for writing out enhancements [" + file.getAbsolutePath() + "]" );
|
||||
}
|
||||
|
||||
try {
|
||||
Files.write( file.toPath(), enhancedBytecode );
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
throw new GradleException( "Error opening class file for writing : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Error writing enhanced class to file [" + file.getAbsolutePath() + "]", e );
|
||||
}
|
||||
}
|
||||
|
||||
private EnhancementHelper() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.enhance;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.HibernateOrmSpec;
|
||||
|
||||
/**
|
||||
* DSL extension for configuring bytecode enhancement - available as `project.hibernateOrm.enhancement`
|
||||
*/
|
||||
@SuppressWarnings( { "unused", "RedundantSuppression" } )
|
||||
public class EnhancementSpec {
|
||||
public static final String ENHANCE = "enhance";
|
||||
public static final String ENHANCEMENT = "enhancement";
|
||||
|
||||
public static final String DSL_NAME = ENHANCEMENT;
|
||||
|
||||
private final Property<Boolean> enableLazyInitialization;
|
||||
private final Property<Boolean> enableDirtyTracking;
|
||||
private final Property<Boolean> enableAssociationManagement;
|
||||
private final Property<Boolean> enableExtendedEnhancement;
|
||||
|
||||
|
||||
@Inject
|
||||
public EnhancementSpec(HibernateOrmSpec ormDsl, Project project) {
|
||||
enableLazyInitialization = makeProperty( project );
|
||||
enableDirtyTracking = makeProperty( project );
|
||||
enableAssociationManagement = makeProperty( project );
|
||||
enableExtendedEnhancement = makeProperty( project );
|
||||
}
|
||||
|
||||
public boolean hasAnythingToDo() {
|
||||
return enableLazyInitialization.get()
|
||||
|| enableDirtyTracking.get()
|
||||
|| enableAssociationManagement.get()
|
||||
|| enableExtendedEnhancement.get();
|
||||
}
|
||||
|
||||
public Property<Boolean> getEnableLazyInitialization() {
|
||||
return enableLazyInitialization;
|
||||
}
|
||||
|
||||
public void setEnableLazyInitialization(boolean enable) {
|
||||
enableLazyInitialization.set( enable );
|
||||
}
|
||||
|
||||
public void enableLazyInitialization(boolean enable) {
|
||||
setEnableLazyInitialization( enable );
|
||||
}
|
||||
|
||||
public void lazyInitialization(boolean enable) {
|
||||
setEnableLazyInitialization( enable );
|
||||
}
|
||||
|
||||
public void setLazyInitialization(boolean enable) {
|
||||
setEnableLazyInitialization( enable );
|
||||
}
|
||||
|
||||
|
||||
public Property<Boolean> getEnableDirtyTracking() {
|
||||
return enableDirtyTracking;
|
||||
}
|
||||
|
||||
public void setEnableDirtyTracking(boolean enable) {
|
||||
enableDirtyTracking.set( enable );
|
||||
}
|
||||
|
||||
public void enableDirtyTracking(boolean enable) {
|
||||
setEnableDirtyTracking( enable );
|
||||
}
|
||||
|
||||
public void dirtyTracking(boolean enable) {
|
||||
setEnableDirtyTracking( enable );
|
||||
}
|
||||
|
||||
public void setDirtyTracking(boolean enable) {
|
||||
setEnableDirtyTracking( enable );
|
||||
}
|
||||
|
||||
|
||||
public Property<Boolean> getEnableAssociationManagement() {
|
||||
return enableAssociationManagement;
|
||||
}
|
||||
|
||||
public void setEnableAssociationManagement(boolean enable) {
|
||||
enableAssociationManagement.set( enable );
|
||||
}
|
||||
|
||||
public void enableAssociationManagement(boolean enable) {
|
||||
setEnableAssociationManagement( enable );
|
||||
}
|
||||
|
||||
public void associationManagement(boolean enable) {
|
||||
setEnableAssociationManagement( enable );
|
||||
}
|
||||
|
||||
|
||||
public Property<Boolean> getEnableExtendedEnhancement() {
|
||||
return enableExtendedEnhancement;
|
||||
}
|
||||
|
||||
public void setEnableExtendedEnhancement(boolean enable) {
|
||||
enableExtendedEnhancement.set( enable );
|
||||
}
|
||||
|
||||
public void enableExtendedEnhancement(boolean enable) {
|
||||
setEnableExtendedEnhancement( enable );
|
||||
}
|
||||
|
||||
public void extendedEnhancement(boolean enable) {
|
||||
setEnableExtendedEnhancement( enable );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public static Property<Boolean> makeProperty(Project project) {
|
||||
final Property<Boolean> createdProperty = project.getObjects().property( Boolean.class );
|
||||
// default to false
|
||||
createdProperty.convention( false );
|
||||
return createdProperty;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.enhance;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.execution.TaskExecutionAdapter;
|
||||
import org.gradle.api.execution.TaskExecutionGraph;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.tasks.InputDirectory;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.api.tasks.TaskState;
|
||||
import org.gradle.work.Incremental;
|
||||
import org.gradle.work.InputChanges;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.HibernateOrmSpec;
|
||||
|
||||
import static org.hibernate.orm.tooling.gradle.HibernateOrmSpec.HIBERNATE;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EnhancementTask extends DefaultTask {
|
||||
public static final String DSL_NAME = "hibernateEnhance";
|
||||
|
||||
public static void apply(HibernateOrmSpec ormDsl, SourceSet mainSourceSet, Project project) {
|
||||
final EnhancementTask enhancementTask = project.getTasks().create(
|
||||
DSL_NAME,
|
||||
EnhancementTask.class,
|
||||
ormDsl,
|
||||
mainSourceSet,
|
||||
project
|
||||
);
|
||||
enhancementTask.setGroup( HIBERNATE );
|
||||
enhancementTask.setDescription( "Performs Hibernate ORM enhancement of the project's compiled classes" );
|
||||
|
||||
final String compileJavaTaskName = mainSourceSet.getCompileJavaTaskName();
|
||||
final Task compileJavaTask = project.getTasks().getByName( compileJavaTaskName );
|
||||
enhancementTask.dependsOn( compileJavaTask );
|
||||
compileJavaTask.finalizedBy( enhancementTask );
|
||||
}
|
||||
|
||||
private final EnhancementSpec enhancementDsl;
|
||||
private final DirectoryProperty javaCompileOutputDirectory;
|
||||
private final DirectoryProperty outputDirectory;
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public EnhancementTask(HibernateOrmSpec ormSpec, SourceSet mainSourceSet, Project project) {
|
||||
this.enhancementDsl = ormSpec.getEnhancementSpec();
|
||||
|
||||
javaCompileOutputDirectory = mainSourceSet.getJava().getDestinationDirectory();
|
||||
|
||||
outputDirectory = project.getObjects().directoryProperty();
|
||||
outputDirectory.set( project.getLayout().getBuildDirectory().dir( "tmp/hibernateEnhancement" ) );
|
||||
|
||||
final AtomicBoolean didCompileRun = new AtomicBoolean( false );
|
||||
|
||||
final TaskExecutionGraph taskGraph = project.getGradle().getTaskGraph();
|
||||
|
||||
taskGraph.addTaskExecutionListener(
|
||||
new TaskExecutionAdapter() {
|
||||
@Override
|
||||
public void afterExecute(Task task, TaskState state) {
|
||||
super.afterExecute( task, state );
|
||||
if ( "compileJava".equals( task.getName() ) ) {
|
||||
if ( state.getDidWork() ) {
|
||||
didCompileRun.set( true );
|
||||
}
|
||||
}
|
||||
|
||||
taskGraph.removeTaskExecutionListener( this );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
getOutputs().upToDateWhen( (task) -> ! didCompileRun.get() );
|
||||
}
|
||||
|
||||
@InputDirectory
|
||||
@Incremental
|
||||
public DirectoryProperty getJavaCompileDirectory() {
|
||||
return javaCompileOutputDirectory;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
public DirectoryProperty getOutputDirectory() {
|
||||
return outputDirectory;
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void enhanceClasses(InputChanges inputChanges) {
|
||||
if ( !enhancementDsl.hasAnythingToDo() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !inputChanges.isIncremental() ) {
|
||||
getProject().getLogger().debug( "EnhancementTask inputs were not incremental" );
|
||||
}
|
||||
|
||||
if ( enhancementDsl.getEnableExtendedEnhancement().get() ) {
|
||||
// for extended enhancement, we may need to enhance everything...
|
||||
// for now, assume we don't
|
||||
getProject().getLogger().info( "Performing extended enhancement" );
|
||||
}
|
||||
|
||||
EnhancementHelper.enhance( javaCompileOutputDirectory, inputChanges, enhancementDsl, getProject() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.provider.SetProperty;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.HibernateOrmSpec;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JpaMetamodelGenerationSpec {
|
||||
public static final String JPA_METAMODEL = "jpaMetamodel";
|
||||
public static final String DSL_NAME = JPA_METAMODEL;
|
||||
|
||||
private final Property<Boolean> applyGeneratedAnnotation;
|
||||
private final SetProperty<String> suppressions;
|
||||
private final DirectoryProperty generationOutputDirectory;
|
||||
private final DirectoryProperty compileOutputDirectory;
|
||||
|
||||
private final Provider<JavaVersion> targetJavaVersionAccess;
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public JpaMetamodelGenerationSpec(HibernateOrmSpec ormDsl, Project project) {
|
||||
applyGeneratedAnnotation = project.getObjects().property( Boolean.class );
|
||||
applyGeneratedAnnotation.convention( true );
|
||||
|
||||
suppressions = project.getObjects().setProperty( String.class );
|
||||
suppressions.convention( Arrays.asList( "raw", "deprecation" ) );
|
||||
|
||||
generationOutputDirectory = project.getObjects().directoryProperty();
|
||||
generationOutputDirectory.convention(
|
||||
project.getLayout().getBuildDirectory().dir( "generated/sources/" + JPA_METAMODEL )
|
||||
);
|
||||
|
||||
compileOutputDirectory = project.getObjects().directoryProperty();
|
||||
compileOutputDirectory.convention(
|
||||
project.getLayout().getBuildDirectory().dir( "classes/java/" + JPA_METAMODEL )
|
||||
);
|
||||
|
||||
targetJavaVersionAccess = project.provider(
|
||||
() -> {
|
||||
final JavaPluginConvention javaPluginConvention = project.getConvention().findPlugin( JavaPluginConvention.class );
|
||||
assert javaPluginConvention != null;
|
||||
final SourceSet sourceSet = javaPluginConvention.getSourceSets().getByName( SourceSet.MAIN_SOURCE_SET_NAME );
|
||||
final String compileTaskName = sourceSet.getCompileJavaTaskName();
|
||||
final JavaCompile compileTask = (JavaCompile) project.getTasks().getByName( compileTaskName );
|
||||
return JavaVersion.toVersion( compileTask.getTargetCompatibility() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public Provider<JavaVersion> getTargetJavaVersionAccess() {
|
||||
return targetJavaVersionAccess;
|
||||
}
|
||||
|
||||
public Property<Boolean> getApplyGeneratedAnnotation() {
|
||||
return applyGeneratedAnnotation;
|
||||
}
|
||||
|
||||
public SetProperty<String> getSuppressions() {
|
||||
return suppressions;
|
||||
}
|
||||
|
||||
public DirectoryProperty getGenerationOutputDirectory() {
|
||||
return generationOutputDirectory;
|
||||
}
|
||||
|
||||
public DirectoryProperty getCompileOutputDirectory() {
|
||||
return compileOutputDirectory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import javax.inject.Inject;
|
||||
import javax.persistence.SharedCacheMode;
|
||||
import javax.persistence.ValidationMode;
|
||||
import javax.persistence.spi.ClassTransformer;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.file.ConfigurableFileTree;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.file.FileCollection;
|
||||
import org.gradle.api.tasks.InputFiles;
|
||||
import org.gradle.api.tasks.OutputDirectory;
|
||||
import org.gradle.api.tasks.SkipWhenEmpty;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetOutput;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.hibernate.orm.tooling.gradle.Helper;
|
||||
import org.hibernate.orm.tooling.gradle.HibernateOrmSpec;
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.model.JpaStaticMetamodelGenerator;
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.model.MetamodelClass;
|
||||
|
||||
import static org.hibernate.orm.tooling.gradle.HibernateOrmSpec.HIBERNATE;
|
||||
|
||||
/**
|
||||
* Generates the "JPA static metamodel" from the domain model defined by the project
|
||||
* via classes and possibly XML mappings
|
||||
*
|
||||
* @apiNote While there is also an annotation-processor that performs the same
|
||||
* general function, that approach is limited in that it can only process compiled
|
||||
* classes based on annotations. This task accounts for both classes and XML mappings
|
||||
*/
|
||||
public class JpaMetamodelGenerationTask extends DefaultTask {
|
||||
public static final String DSL_NAME = "generateJpaMetamodel";
|
||||
public static final String COMPILE_DSL_NAME = "compileJpaMetamodel";
|
||||
|
||||
|
||||
private final HibernateOrmSpec ormSpec;
|
||||
private final DirectoryProperty resourcesOutputDir;
|
||||
private final SourceSet mainSourceSet;
|
||||
|
||||
@Inject
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public JpaMetamodelGenerationTask(
|
||||
HibernateOrmSpec ormSpec,
|
||||
SourceSet mainSourceSet,
|
||||
JavaCompile mainCompileTask,
|
||||
Project project) {
|
||||
this.ormSpec = ormSpec;
|
||||
dependsOn( mainCompileTask );
|
||||
|
||||
this.mainSourceSet = mainSourceSet;
|
||||
|
||||
final SourceSetOutput mainSourceSetOutput = mainSourceSet.getOutput();
|
||||
|
||||
resourcesOutputDir = project.getObjects().directoryProperty();
|
||||
resourcesOutputDir.set( project.getLayout().dir( project.provider( mainSourceSetOutput::getResourcesDir ) ) );
|
||||
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
@SkipWhenEmpty
|
||||
public FileCollection getJavaClassDirs() {
|
||||
return mainSourceSet.getOutput();
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
@SkipWhenEmpty
|
||||
public DirectoryProperty getResourcesOutputDir() {
|
||||
// for access to XML mappings
|
||||
return resourcesOutputDir;
|
||||
}
|
||||
|
||||
@OutputDirectory
|
||||
public DirectoryProperty getGenerationOutputDirectory() {
|
||||
return ormSpec.getJpaMetamodelSpec().getGenerationOutputDirectory();
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void generateJpaMetamodel() {
|
||||
final ClassLoader classLoader = determineUnitClassLoader( getProject(), mainSourceSet );
|
||||
final PersistenceUnitInfoImpl unitInfo = new PersistenceUnitInfoImpl(
|
||||
determineUnitUrl(),
|
||||
generateIntegrationSettings(),
|
||||
classLoader
|
||||
);
|
||||
|
||||
getJavaClassDirs().forEach(
|
||||
classesDir -> {
|
||||
final ConfigurableFileTree files = getProject().fileTree( classesDir );
|
||||
files.forEach(
|
||||
file -> {
|
||||
if ( file.getName().endsWith( ".class" ) ) {
|
||||
final String className = Helper.determineClassName( classesDir, file );
|
||||
unitInfo.addManagedClassName( className );
|
||||
}
|
||||
else if ( isMappingFile( file ) ) {
|
||||
unitInfo.addMappingFile( file.getName() );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
resourcesOutputDir.getAsFileTree().forEach(
|
||||
file -> {
|
||||
if ( isMappingFile( file ) ) {
|
||||
unitInfo.addMappingFile( file.getName() );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
JpaStaticMetamodelGenerator.processMetamodel( unitInfo, ormSpec.getJpaMetamodelSpec() );
|
||||
}
|
||||
|
||||
private URL determineUnitUrl() {
|
||||
try {
|
||||
// NOTE : we just need *a* URL - we used the project dir
|
||||
return getProject().getProjectDir().toURI().toURL();
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new IllegalStateException( "Could not interpret project directory as URL" );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
private static ClassLoader determineUnitClassLoader(Project project, SourceSet mainSourceSet) {
|
||||
final String compileJavaTaskName = mainSourceSet.getCompileJavaTaskName();
|
||||
final JavaCompile javaCompileTask = (JavaCompile) project.getTasks().getByName( compileJavaTaskName );
|
||||
final URL projectClassesDirUrl = toUrl( javaCompileTask.getDestinationDirectory().get().getAsFile() );
|
||||
|
||||
return new URLClassLoader( new URL[] { projectClassesDirUrl }, MetamodelClass.class.getClassLoader() );
|
||||
}
|
||||
|
||||
private static URL toUrl(File file) {
|
||||
final URI uri = file.toURI();
|
||||
try {
|
||||
return uri.toURL();
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new GradleException( "Could not convert classpath entry into URL : " + file.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private Properties generateIntegrationSettings() {
|
||||
final Properties settings = new Properties();
|
||||
|
||||
settings.put( "hibernate.temp.use_jdbc_metadata_defaults", "false" );
|
||||
settings.put( AvailableSettings.DIALECT, "H2" );
|
||||
settings.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, false );
|
||||
settings.put( AvailableSettings.USE_QUERY_CACHE, false );
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
private boolean isMappingFile(File file) {
|
||||
final String fileName = file.getName();
|
||||
|
||||
// convention
|
||||
// - we could allow filters for flexibility?
|
||||
return fileName.endsWith( ".hbm.xml" ) || fileName.endsWith( ".orm.xml" );
|
||||
}
|
||||
|
||||
private static class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
|
||||
private final URL unitRoot;
|
||||
private final Properties properties;
|
||||
private final ClassLoader classLoader;
|
||||
private final List<String> managedClassNames = new ArrayList<>();
|
||||
private final List<String> mappingFileNames = new ArrayList<>();
|
||||
|
||||
public PersistenceUnitInfoImpl(URL unitRoot, Properties properties, ClassLoader classLoader) {
|
||||
this.unitRoot = unitRoot;
|
||||
this.properties = properties;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPersistenceUnitName() {
|
||||
return "jpa-static-metamodel-gen";
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getPersistenceUnitRootUrl() {
|
||||
return unitRoot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Properties getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getManagedClassNames() {
|
||||
return managedClassNames;
|
||||
}
|
||||
|
||||
public void addManagedClassName(String className) {
|
||||
getManagedClassNames().add( className );
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMappingFileNames() {
|
||||
return mappingFileNames;
|
||||
}
|
||||
|
||||
public void addMappingFile(String fileName) {
|
||||
getMappingFileNames().add( fileName );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getPersistenceProviderClassName() {
|
||||
return HibernatePersistenceProvider.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceUnitTransactionType getTransactionType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSource getJtaDataSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSource getNonJtaDataSource() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<URL> getJarFileUrls() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean excludeUnlistedClasses() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SharedCacheMode getSharedCacheMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationMode getValidationMode() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPersistenceXMLSchemaVersion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTransformer(ClassTransformer transformer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getNewTempClassLoader() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( "UnstableApiUsage" )
|
||||
public static void apply(HibernateOrmSpec ormDsl, SourceSet mainSourceSet, Project project) {
|
||||
final String mainCompileTaskName = mainSourceSet.getCompileJavaTaskName();
|
||||
final JavaCompile mainCompileTask = (JavaCompile) project.getTasks().getByName( mainCompileTaskName );
|
||||
|
||||
final JpaMetamodelGenerationTask genTask = project.getTasks().create(
|
||||
DSL_NAME,
|
||||
JpaMetamodelGenerationTask.class,
|
||||
ormDsl,
|
||||
mainSourceSet,
|
||||
mainCompileTask,
|
||||
project
|
||||
);
|
||||
genTask.setGroup( HIBERNATE );
|
||||
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 );
|
||||
compileJpaMetamodelTask.setGroup( HIBERNATE );
|
||||
compileJpaMetamodelTask.setDescription( "Compiles the JPA static metamodel generated by `" + DSL_NAME + "`" );
|
||||
compileJpaMetamodelTask.setSourceCompatibility( mainCompileTask.getSourceCompatibility() );
|
||||
compileJpaMetamodelTask.setTargetCompatibility( mainCompileTask.getTargetCompatibility() );
|
||||
genTask.finalizedBy( compileJpaMetamodelTask );
|
||||
compileJpaMetamodelTask.dependsOn( genTask );
|
||||
compileJpaMetamodelTask.source( project.files( ormDsl.getJpaMetamodelSpec().getGenerationOutputDirectory() ) );
|
||||
compileJpaMetamodelTask.getDestinationDirectory().set( ormDsl.getJpaMetamodelSpec().getCompileOutputDirectory() );
|
||||
compileJpaMetamodelTask.setClasspath(
|
||||
project.getConfigurations().getByName( "runtimeClasspath" ).plus( mainSourceSet.getRuntimeClasspath() )
|
||||
);
|
||||
|
||||
compileJpaMetamodelTask.doFirst(
|
||||
(task) -> {
|
||||
project.getLogger().lifecycle( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
|
||||
project.getLogger().lifecycle( "compileJpaMetamodel classpath" );
|
||||
project.getLogger().lifecycle( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
|
||||
( (JavaCompile) task ).getClasspath().forEach(
|
||||
entry -> project.getLogger().lifecycle( " > {}", entry.getAbsolutePath() )
|
||||
);
|
||||
project.getLogger().lifecycle( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
public class AttributeBag extends AttributeSupport {
|
||||
private final Class<?> elementJavaType;
|
||||
|
||||
public AttributeBag(
|
||||
MetamodelClass metamodelClass,
|
||||
String attributeName,
|
||||
Class<?> elementJavaType) {
|
||||
super( metamodelClass, attributeName, Collection.class );
|
||||
this.elementJavaType = elementJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAttributeType(BufferedWriter writer) throws IOException {
|
||||
writer.write(
|
||||
format(
|
||||
"CollectionAttribute<%s,%s>",
|
||||
getOwnerDomainClassName(),
|
||||
elementJavaType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
public class AttributeList extends AttributeSupport {
|
||||
private final Class<?> elementJavaType;
|
||||
|
||||
public AttributeList(
|
||||
MetamodelClass metamodelClass,
|
||||
String attributeName,
|
||||
Class<?> elementJavaType) {
|
||||
super( metamodelClass, attributeName, Set.class );
|
||||
this.elementJavaType = elementJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAttributeType(BufferedWriter writer) throws IOException {
|
||||
writer.write(
|
||||
format(
|
||||
"ListAttribute<%s,%s>",
|
||||
getOwnerDomainClassName(),
|
||||
elementJavaType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
public class AttributeMap extends AttributeSupport {
|
||||
private final Class<?> keyJavaType;
|
||||
private final Class<?> elementJavaType;
|
||||
|
||||
public AttributeMap(
|
||||
MetamodelClass metamodelClass,
|
||||
String attributeName,
|
||||
Class<?> keyJavaType,
|
||||
Class<?> elementJavaType) {
|
||||
super( metamodelClass, attributeName, Set.class );
|
||||
this.keyJavaType = keyJavaType;
|
||||
this.elementJavaType = elementJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAttributeType(BufferedWriter writer) throws IOException {
|
||||
writer.write(
|
||||
format(
|
||||
"MapAttribute<%s,%s,%s>",
|
||||
getOwnerDomainClassName(),
|
||||
keyJavaType.getName(),
|
||||
elementJavaType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
|
||||
public class AttributeSet extends AttributeSupport {
|
||||
private final Class<?> elementJavaType;
|
||||
|
||||
public AttributeSet(
|
||||
MetamodelClass metamodelClass,
|
||||
String attributeName,
|
||||
Class<?> elementJavaType) {
|
||||
super( metamodelClass, attributeName, Set.class );
|
||||
this.elementJavaType = elementJavaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAttributeType(BufferedWriter writer) throws IOException {
|
||||
writer.write(
|
||||
format(
|
||||
"SetAttribute<%s,%s>",
|
||||
getOwnerDomainClassName(),
|
||||
elementJavaType.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
public class AttributeSingular extends AttributeSupport {
|
||||
|
||||
public AttributeSingular(MetamodelClass metamodelClass, String name, Class javaType) {
|
||||
super( metamodelClass, name, javaType );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderAttributeType(BufferedWriter writer) throws IOException {
|
||||
// JPA stuff already imported
|
||||
writer.write(
|
||||
format(
|
||||
"SingularAttribute<%s,%s>",
|
||||
getOwnerDomainClassName(),
|
||||
getAttributeJavaType().getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import static java.lang.Character.LINE_SEPARATOR;
|
||||
|
||||
public abstract class AttributeSupport implements MetamodelAttribute {
|
||||
private final MetamodelClass metamodelClass;
|
||||
private final String name;
|
||||
private final Class<?> javaType;
|
||||
|
||||
public AttributeSupport(
|
||||
MetamodelClass metamodelClass,
|
||||
String name,
|
||||
Class<?> javaType) {
|
||||
this.metamodelClass = metamodelClass;
|
||||
this.name = name;
|
||||
this.javaType = javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getAttributeJavaType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
public String getOwnerDomainClassName() {
|
||||
return metamodelClass.getMetamodelClassName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderJpaMembers(BufferedWriter writer) {
|
||||
try {
|
||||
writer.write( " public static volatile " );
|
||||
renderAttributeType( writer );
|
||||
writer.write( " " + name );
|
||||
writer.write( ';' );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException( "Problem writing attribute `" + metamodelClass.getMetamodelClassName() + "#" + name + "` to output stream", e );
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void renderAttributeType(BufferedWriter writer) throws IOException;
|
||||
|
||||
protected String format(String pattern, Object... args) {
|
||||
return String.format( Locale.ROOT, pattern, args );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderNameConstant(BufferedWriter writer) {
|
||||
try {
|
||||
writer.write( " public static final String " );
|
||||
writer.write( getName().toUpperCase( Locale.ROOT ) );
|
||||
writer.write( " = \"" + getName() + "\";" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException( "Problem writing attribute `" + metamodelClass.getMetamodelClassName() + "#" + name + "` to output stream", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import javax.persistence.spi.PersistenceUnitInfo;
|
||||
|
||||
import org.gradle.api.file.Directory;
|
||||
import org.gradle.api.file.RegularFile;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.jpa.boot.spi.Bootstrap;
|
||||
import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.JpaMetamodelGenerationSpec;
|
||||
|
||||
public class JpaStaticMetamodelGenerator {
|
||||
public static void processMetamodel(
|
||||
PersistenceUnitInfo persistenceUnitInfo,
|
||||
JpaMetamodelGenerationSpec spec) {
|
||||
EntityManagerFactoryBuilder target = Bootstrap.getEntityManagerFactoryBuilder( persistenceUnitInfo, Collections.emptyMap() );
|
||||
try {
|
||||
new JpaStaticMetamodelGenerator( spec, target.metadata() ).process();
|
||||
}
|
||||
finally {
|
||||
target.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private final JpaMetamodelGenerationSpec spec;
|
||||
private final MetadataImplementor metadata;
|
||||
|
||||
private final Directory generationOutputDirectory;
|
||||
private final ObjectFactory objectFactory;
|
||||
|
||||
private final Set<String> processedDomainTypeNames = new HashSet<>();
|
||||
|
||||
private JpaStaticMetamodelGenerator(JpaMetamodelGenerationSpec spec, MetadataImplementor metadata) {
|
||||
this.spec = spec;
|
||||
this.metadata = metadata;
|
||||
this.generationOutputDirectory = spec.getGenerationOutputDirectory().get();
|
||||
this.objectFactory = new ObjectFactory( metadata );
|
||||
}
|
||||
|
||||
private void process() {
|
||||
final Set<MappedSuperclass> mappedSuperclasses = metadata.getMappedSuperclassMappingsCopy();
|
||||
if ( mappedSuperclasses != null ) {
|
||||
mappedSuperclasses.forEach( this::handleMappedClass );
|
||||
}
|
||||
|
||||
final java.util.Collection<PersistentClass> entityBindings = metadata.getEntityBindings();
|
||||
if ( entityBindings != null ) {
|
||||
entityBindings.forEach( this::handlePersistentClass );
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void handleMappedClass(MappedSuperclass mappingDescriptor) {
|
||||
final MetamodelClass metamodelClass = objectFactory.metamodelClass( mappingDescriptor );
|
||||
handleManagedClass( metamodelClass, mappingDescriptor.getDeclaredPropertyIterator() );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void handlePersistentClass(PersistentClass persistentClass) {
|
||||
final MetamodelClass metamodelClass = objectFactory.metamodelClass( persistentClass );
|
||||
handleManagedClass( metamodelClass, persistentClass.getDeclaredPropertyIterator() );
|
||||
}
|
||||
|
||||
private void handleManagedClass(MetamodelClass metamodelClass, Iterator<Property> propertyIterator) {
|
||||
if ( ! processedDomainTypeNames.add( metamodelClass.getDomainClassName() ) ) {
|
||||
// already processed
|
||||
return;
|
||||
}
|
||||
|
||||
propertyIterator.forEachRemaining(
|
||||
property -> metamodelClass.addAttribute(
|
||||
objectFactory.attribute( property, property.getValue(), metamodelClass, this::handleEmbeddable )
|
||||
)
|
||||
);
|
||||
|
||||
final String replaced = metamodelClass.getMetamodelClassName().replace( '.', '/' );
|
||||
final String metamodelClassJavaFileName = replaced + ".java";
|
||||
final RegularFile metamodelClassJavaFile = generationOutputDirectory.file( metamodelClassJavaFileName );
|
||||
|
||||
final File metamodelClassJavaFileAsFile = metamodelClassJavaFile.getAsFile();
|
||||
metamodelClass.writeToFile( metamodelClassJavaFileAsFile, spec );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "unchecked" )
|
||||
private void handleEmbeddable(Component embeddedValueMapping) {
|
||||
final MetamodelClass metamodelClass = objectFactory.metamodelClass( embeddedValueMapping );
|
||||
handleManagedClass( metamodelClass, embeddedValueMapping.getPropertyIterator() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
|
||||
public interface MetamodelAttribute {
|
||||
String getName();
|
||||
|
||||
Class<?> getAttributeJavaType();
|
||||
|
||||
void renderJpaMembers(BufferedWriter writer);
|
||||
|
||||
void renderNameConstant(BufferedWriter writer);
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.JavaVersion;
|
||||
|
||||
import org.hibernate.orm.tooling.gradle.metamodel.JpaMetamodelGenerationSpec;
|
||||
|
||||
import static java.lang.Character.LINE_SEPARATOR;
|
||||
|
||||
/**
|
||||
* Descriptor for a class in the JPA static metamodel being generated
|
||||
*/
|
||||
public class MetamodelClass {
|
||||
|
||||
private final String domainClassName;
|
||||
private final String metamodelClassName;
|
||||
|
||||
private final String metamodelSuperClassName;
|
||||
|
||||
private final TreeSet<MetamodelAttribute> attributes = new TreeSet<>( Comparator.comparing( MetamodelAttribute::getName ) );
|
||||
|
||||
public MetamodelClass(String domainClassName, String superTypeName) {
|
||||
this.domainClassName = domainClassName;
|
||||
this.metamodelClassName = domainClassName + "_";
|
||||
this.metamodelSuperClassName = superTypeName == null ? null : superTypeName + "_";
|
||||
}
|
||||
|
||||
public String getMetamodelClassName() {
|
||||
return metamodelClassName;
|
||||
}
|
||||
|
||||
public String getDomainClassName() {
|
||||
return domainClassName;
|
||||
}
|
||||
|
||||
public void addAttribute(MetamodelAttribute attribute) {
|
||||
assert attribute != null;
|
||||
attributes.add( attribute );
|
||||
}
|
||||
|
||||
public void writeToFile(File outputFile, JpaMetamodelGenerationSpec spec) {
|
||||
prepareOutputFile( outputFile );
|
||||
|
||||
final Path path = outputFile.toPath();
|
||||
|
||||
try ( final BufferedWriter writer = Files.newBufferedWriter( path, StandardCharsets.UTF_8, StandardOpenOption.WRITE ) ) {
|
||||
|
||||
renderClassPreamble( writer, spec );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( "public abstract class " + metamodelClassName );
|
||||
if ( metamodelSuperClassName != null ) {
|
||||
writer.write( " extends " + metamodelSuperClassName );
|
||||
}
|
||||
writer.write( " {" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( " // Attribute name constants" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
attributes.forEach( attribute -> attribute.renderNameConstant( writer ) );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( " // JPA static metamodel fields" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
attributes.forEach( attribute -> attribute.renderJpaMembers( writer ) );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( "}" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException( "Unable to open file : " + outputFile.getAbsolutePath(), e );
|
||||
}
|
||||
}
|
||||
|
||||
private void renderClassPreamble(BufferedWriter writer, JpaMetamodelGenerationSpec spec) throws IOException {
|
||||
final String nowFormatted = DateFormat.getDateInstance().format( new Date() );
|
||||
|
||||
writer.write( "// Generated by Hibernate ORM Gradle tooling - " + nowFormatted );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( "import javax.persistence.*;" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
writer.write( "import javax.persistence.metamodel.*;" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
writer.write( "/** JPA static metamodel descriptor for the `" + domainClassName + "` domain class */" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
|
||||
// first, the generated annotation
|
||||
if ( spec.getApplyGeneratedAnnotation().getOrElse( true ) ) {
|
||||
final JavaVersion javaVersion = spec.getTargetJavaVersionAccess().getOrElse( JavaVersion.current() );
|
||||
final String qualifiedAnnotationName = javaVersion.isJava9Compatible()
|
||||
? "javax.annotation.processing.Generated"
|
||||
: "javax.annotation.Generated";
|
||||
final String generatedAnnotationFragment = String.format(
|
||||
Locale.ROOT,
|
||||
"@%s( value=\"%s\", date=\"%s\", comments=\"%s\" )",
|
||||
qualifiedAnnotationName,
|
||||
JpaStaticMetamodelGenerator.class.getName(),
|
||||
nowFormatted,
|
||||
"Generated by Hibernate ORM Gradle tooling"
|
||||
);
|
||||
writer.write( generatedAnnotationFragment );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
}
|
||||
|
||||
final Set<String> suppressions = spec.getSuppressions().getOrElse( Collections.emptySet() );
|
||||
if ( ! suppressions.isEmpty() ) {
|
||||
writer.write( "@SuppressWarnings( { " );
|
||||
for ( String suppression : suppressions ) {
|
||||
writer.write( "\"" + suppression + "\", " );
|
||||
}
|
||||
writer.write( " } )" );
|
||||
writer.write( LINE_SEPARATOR );
|
||||
}
|
||||
|
||||
writer.write( "@StaticMetamodel( " + domainClassName + ".class )" );
|
||||
}
|
||||
|
||||
@SuppressWarnings( "ResultOfMethodCallIgnored" )
|
||||
public void prepareOutputFile(File outputFile) {
|
||||
try {
|
||||
outputFile.getParentFile().mkdirs();
|
||||
outputFile.createNewFile();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new GradleException( "Unable to prepare output file `" + outputFile.getAbsolutePath() + "`", e );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle.metamodel.model;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Bag;
|
||||
import org.hibernate.mapping.BasicValue;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.DependantValue;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.List;
|
||||
import org.hibernate.mapping.Map;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.mapping.OneToMany;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Set;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ObjectFactory {
|
||||
private final MetadataImplementor metadata;
|
||||
|
||||
public ObjectFactory(MetadataImplementor metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public MetamodelClass metamodelClass(PersistentClass entityDescriptor) {
|
||||
return new MetamodelClass( entityDescriptor.getMappedClass().getName(), determineSuperTypeName( entityDescriptor ) );
|
||||
}
|
||||
|
||||
private String determineSuperTypeName(PersistentClass entityDescriptor) {
|
||||
if ( entityDescriptor.getSuperMappedSuperclass() != null ) {
|
||||
return entityDescriptor.getSuperMappedSuperclass().getMappedClass().getName();
|
||||
}
|
||||
|
||||
if ( entityDescriptor.getSuperclass() != null ) {
|
||||
return entityDescriptor.getSuperclass().getMappedClass().getName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MetamodelClass metamodelClass(MappedSuperclass mappedSuperclassDescriptor) {
|
||||
return new MetamodelClass( mappedSuperclassDescriptor.getMappedClass().getName(), determineSuperTypeName( mappedSuperclassDescriptor ) );
|
||||
}
|
||||
|
||||
private String determineSuperTypeName(MappedSuperclass mappedSuperclassDescriptor) {
|
||||
if ( mappedSuperclassDescriptor.getSuperMappedSuperclass() != null ) {
|
||||
return mappedSuperclassDescriptor.getSuperMappedSuperclass().getMappedClass().getName();
|
||||
}
|
||||
|
||||
if ( mappedSuperclassDescriptor.getSuperPersistentClass() != null ) {
|
||||
return mappedSuperclassDescriptor.getSuperPersistentClass().getMappedClass().getName();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MetamodelClass metamodelClass(Component embeddedMapping) {
|
||||
return new MetamodelClass( embeddedMapping.getComponentClassName(), null );
|
||||
}
|
||||
|
||||
public MetamodelAttribute attribute(
|
||||
Property property,
|
||||
Value propertyValueMapping,
|
||||
MetamodelClass metamodelClass,
|
||||
Consumer<Component> componentConsumer) {
|
||||
if ( propertyValueMapping instanceof DependantValue ) {
|
||||
final DependantValue dependantValue = (DependantValue) propertyValueMapping;
|
||||
final KeyValue wrappedValue = dependantValue.getWrappedValue();
|
||||
return attribute( property, wrappedValue, metamodelClass, componentConsumer );
|
||||
}
|
||||
|
||||
if ( propertyValueMapping instanceof Collection ) {
|
||||
return pluralAttribute( property, (Collection) propertyValueMapping, metamodelClass, componentConsumer );
|
||||
}
|
||||
|
||||
final Class<?> propertyJavaType = determineSingularJavaType( property, propertyValueMapping, metamodelClass, componentConsumer );
|
||||
return new AttributeSingular( metamodelClass, property.getName(), propertyJavaType );
|
||||
}
|
||||
|
||||
private Class<?> determineSingularJavaType(
|
||||
Property property,
|
||||
Value propertyValueMapping,
|
||||
MetamodelClass metamodelClass,
|
||||
Consumer<Component> componentConsumer) {
|
||||
if ( propertyValueMapping instanceof BasicValue ) {
|
||||
final BasicValue basicValue = (BasicValue) propertyValueMapping;
|
||||
return basicValue.resolve().getDomainJavaDescriptor().getJavaType();
|
||||
}
|
||||
|
||||
if ( propertyValueMapping instanceof Component ) {
|
||||
final Component component = (Component) propertyValueMapping;
|
||||
componentConsumer.accept( component );
|
||||
return component.getComponentClass();
|
||||
}
|
||||
|
||||
if ( propertyValueMapping instanceof Any ) {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
if ( propertyValueMapping instanceof ToOne ) {
|
||||
final ToOne toOne = (ToOne) propertyValueMapping;
|
||||
final String referencedEntityName = toOne.getReferencedEntityName();
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( referencedEntityName );
|
||||
final Class<?> mappedClass = entityBinding.getMappedClass();
|
||||
if ( mappedClass == null ) {
|
||||
throw new GradleException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not determine ToOne java type : %s#%s",
|
||||
metamodelClass.getDomainClassName(),
|
||||
property.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
return mappedClass;
|
||||
}
|
||||
|
||||
propertyValueMapping.setTypeUsingReflection( metamodelClass.getDomainClassName(), property.getName() );
|
||||
return propertyValueMapping.getType().getReturnedClass();
|
||||
}
|
||||
|
||||
private MetamodelAttribute pluralAttribute(
|
||||
Property property,
|
||||
Collection collectionMapping,
|
||||
MetamodelClass metamodelClass,
|
||||
Consumer<Component> componentConsumer) {
|
||||
if ( collectionMapping instanceof Set ) {
|
||||
return new AttributeSet(
|
||||
metamodelClass,
|
||||
property.getName(),
|
||||
determineCollectionPartJavaType( property, collectionMapping.getElement(), metamodelClass, componentConsumer )
|
||||
);
|
||||
}
|
||||
|
||||
if ( collectionMapping instanceof Bag ) {
|
||||
return new AttributeBag(
|
||||
metamodelClass,
|
||||
property.getName(),
|
||||
determineCollectionPartJavaType( property, collectionMapping.getElement(), metamodelClass, componentConsumer )
|
||||
);
|
||||
}
|
||||
|
||||
if ( collectionMapping instanceof List ) {
|
||||
return new AttributeList(
|
||||
metamodelClass,
|
||||
property.getName(),
|
||||
determineCollectionPartJavaType( property, collectionMapping.getElement(), metamodelClass, componentConsumer )
|
||||
);
|
||||
}
|
||||
|
||||
if ( collectionMapping instanceof Map ) {
|
||||
return new AttributeMap(
|
||||
metamodelClass,
|
||||
property.getName(),
|
||||
determineCollectionPartJavaType( property, ( (Map) collectionMapping ).getIndex(), metamodelClass, componentConsumer ),
|
||||
determineCollectionPartJavaType( property, collectionMapping.getElement(), metamodelClass, componentConsumer )
|
||||
);
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException( "Unsupported plural value type : " + collectionMapping.getClass().getName() );
|
||||
}
|
||||
|
||||
private Class<?> determineCollectionPartJavaType(
|
||||
Property property,
|
||||
Value partJavaType,
|
||||
MetamodelClass metamodelClass,
|
||||
Consumer<Component> componentConsumer) {
|
||||
if ( partJavaType instanceof DependantValue ) {
|
||||
final DependantValue dependantValue = (DependantValue) partJavaType;
|
||||
final KeyValue wrappedValue = dependantValue.getWrappedValue();
|
||||
return determineCollectionPartJavaType( property, wrappedValue, metamodelClass, componentConsumer );
|
||||
}
|
||||
|
||||
if ( partJavaType instanceof BasicValue ) {
|
||||
final BasicValue basicValue = (BasicValue) partJavaType;
|
||||
return basicValue.resolve().getDomainJavaDescriptor().getJavaType();
|
||||
}
|
||||
|
||||
if ( partJavaType instanceof Component ) {
|
||||
final Component component = (Component) partJavaType;
|
||||
componentConsumer.accept( component );
|
||||
return component.getComponentClass();
|
||||
}
|
||||
|
||||
if ( partJavaType instanceof Any ) {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
if ( partJavaType instanceof OneToMany ) {
|
||||
final OneToMany oneToMany = (OneToMany) partJavaType;
|
||||
final PersistentClass associatedClass = oneToMany.getAssociatedClass();
|
||||
return associatedClass.getMappedClass();
|
||||
}
|
||||
|
||||
if ( partJavaType instanceof ToOne ) {
|
||||
final ToOne toOne = (ToOne) partJavaType;
|
||||
final String referencedEntityName = toOne.getReferencedEntityName();
|
||||
if ( referencedEntityName != null ) {
|
||||
final PersistentClass entityBinding = metadata.getEntityBinding( referencedEntityName );
|
||||
if ( entityBinding != null ) {
|
||||
final Class<?> mappedClass = entityBinding.getMappedClass();
|
||||
if ( mappedClass != null ) {
|
||||
return mappedClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new GradleException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not determine ToOne java type : %s#%s",
|
||||
metamodelClass.getDomainClassName(),
|
||||
property.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return partJavaType.getType().getReturnedClass();
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
#
|
||||
# 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>.
|
||||
#
|
||||
implementation-class=org.hibernate.orm.tooling.gradle.HibernatePlugin
|
|
@ -0,0 +1 @@
|
|||
@hibernateVersion@
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.assertNotNull
|
||||
/**
|
||||
* Test what we can. ProjectBuilder is better than nothing, but still quited limited in what
|
||||
* you can test (e.g. you cannot test task execution).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
class HibernatePluginTest {
|
||||
@Test
|
||||
public void testHibernatePluginAddsExtension() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
assertNotNull( project.extensions.findByName( "hibernate" ) )
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHibernateExtensionConfig() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
project.extensions.findByType( HibernateExtension.class ).enhance {
|
||||
enableLazyInitialization = true
|
||||
enableDirtyTracking = true
|
||||
enableAssociationManagement = false
|
||||
enableExtendedEnhancement = false
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhanceTask() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
def task = project.tasks.create( "finishHim", EnhanceTask )
|
||||
|
||||
task.options {
|
||||
enableLazyInitialization = true
|
||||
enableDirtyTracking = true
|
||||
enableAssociationManagement = false
|
||||
enableExtendedEnhancement = false
|
||||
}
|
||||
|
||||
task.sourceSets = project.getConvention().getPlugin( JavaPluginConvention ).sourceSets.main
|
||||
|
||||
task.enhance()
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskAction() {
|
||||
Project project = ProjectBuilder.builder().build()
|
||||
project.plugins.apply 'org.hibernate.orm'
|
||||
|
||||
// the test sourceSet
|
||||
def sourceSet = project.getConvention().getPlugin( JavaPluginConvention ).sourceSets.test;
|
||||
|
||||
// The compile task for the test sourceSet
|
||||
final JavaCompile compileTestTask = project.getTasks().findByName( sourceSet.getCompileJavaTaskName() );
|
||||
|
||||
// Lets add our enhancer to enhance the test classes after the test are compiled
|
||||
compileTestTask.doLast {
|
||||
EnhancementHelper.enhance(
|
||||
sourceSet,
|
||||
project.extensions.findByType( HibernateExtension.class ).enhance,
|
||||
project
|
||||
)
|
||||
}
|
||||
|
||||
// TODO find how to do this in Gradle 5
|
||||
// the class-level javadoc says it's not possible, and it was there in Gradle 4.x...
|
||||
//compileTestTask.execute()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.orm.tooling.gradle;
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult;
|
||||
import org.gradle.testkit.runner.BuildTask;
|
||||
import org.gradle.testkit.runner.GradleRunner;
|
||||
import org.gradle.testkit.runner.TaskOutcome;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.github.sebersole.testkit.Project;
|
||||
import com.github.sebersole.testkit.ProjectScope;
|
||||
import com.github.sebersole.testkit.TestKit;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* Test what we can. TestKit is better than nothing, but still somewhat limited in what
|
||||
* you can test in my experience
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@TestKit
|
||||
class HibernateOrmPluginTest {
|
||||
@Test
|
||||
public void testEnhancementTaskAsFinalizer(@Project( "simple" ) ProjectScope projectScope) {
|
||||
final GradleRunner gradleRunner = projectScope.createGradleRunner( "clean", "compileJava" );
|
||||
final BuildResult result = gradleRunner.build();
|
||||
final BuildTask task = result.task( ":hibernateEnhance" );
|
||||
assert task != null;
|
||||
|
||||
assertThat(
|
||||
task.getOutcome(),
|
||||
anyOf( is( TaskOutcome.SUCCESS ), is( TaskOutcome.UP_TO_DATE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhancementTask(@Project( "simple" ) ProjectScope projectScope) {
|
||||
final GradleRunner gradleRunner = projectScope.createGradleRunner(
|
||||
"clean",
|
||||
"hibernateEnhance"
|
||||
);
|
||||
final BuildResult result = gradleRunner.build();
|
||||
final BuildTask task = result.task( ":hibernateEnhance" );
|
||||
assert task != null;
|
||||
|
||||
assertThat( task.getOutcome(), is( TaskOutcome.SUCCESS ) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnhancementTaskUpToDate(@Project( "simple" ) ProjectScope projectScope) {
|
||||
final GradleRunner gradleRunner = projectScope.createGradleRunner(
|
||||
"clean",
|
||||
"hibernateEnhance"
|
||||
);
|
||||
final BuildResult result = gradleRunner.build();
|
||||
final BuildTask task = result.task( ":hibernateEnhance" );
|
||||
assert task != null;
|
||||
|
||||
assertThat(
|
||||
task.getOutcome(),
|
||||
anyOf( is( TaskOutcome.SUCCESS ), is( TaskOutcome.UP_TO_DATE ) )
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
// @Disabled( "Problem with ClassPathAndModulePathAggregatedServiceLoader and loading Java services" )
|
||||
public void testJpaMetamodelGen(@Project( "simple" ) ProjectScope projectScope) {
|
||||
final GradleRunner gradleRunner = projectScope.createGradleRunner(
|
||||
"clean",
|
||||
"generateJpaMetamodel"
|
||||
);
|
||||
final BuildResult result = gradleRunner.build();
|
||||
final BuildTask task = result.task( ":generateJpaMetamodel" );
|
||||
assert task != null;
|
||||
|
||||
assertThat(
|
||||
task.getOutcome(),
|
||||
anyOf( is( TaskOutcome.SUCCESS ), is( TaskOutcome.UP_TO_DATE ) )
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.hibernate.orm'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
name 'jboss-snapshots-repository'
|
||||
url 'https://repository.jboss.org/nexus/content/repositories/snapshots'
|
||||
}
|
||||
}
|
||||
|
||||
hibernate {
|
||||
enhancement {
|
||||
lazyInitialization( true )
|
||||
dirtyTracking = true
|
||||
}
|
||||
jpaMetamodel {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import javax.persistence.Embeddable;
|
||||
|
||||
@Embeddable
|
||||
public class TheEmbeddable {
|
||||
private String valueOne;
|
||||
private String valueTwo;
|
||||
|
||||
public String getValueOne() {
|
||||
return valueOne;
|
||||
}
|
||||
|
||||
public void setValueOne(String valueOne) {
|
||||
this.valueOne = valueOne;
|
||||
}
|
||||
|
||||
public String getValueTwo() {
|
||||
return valueTwo;
|
||||
}
|
||||
|
||||
public void setValueTwo(String valueTwo) {
|
||||
this.valueTwo = valueTwo;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@Entity
|
||||
public class TheEntity {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
@Embedded
|
||||
private TheEmbeddable theEmbeddable;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn
|
||||
private TheEntity theManyToOne;
|
||||
|
||||
@OneToMany( mappedBy = "theManyToOne" )
|
||||
private Set<TheEntity> theOneToMany;
|
||||
|
||||
@ElementCollection
|
||||
@JoinColumn( name = "owner_id" )
|
||||
private Set<TheEmbeddable> theEmbeddableCollection;
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public TheEmbeddable getTheEmbeddable() {
|
||||
return theEmbeddable;
|
||||
}
|
||||
|
||||
public void setTheEmbeddable(TheEmbeddable theEmbeddable) {
|
||||
this.theEmbeddable = theEmbeddable;
|
||||
}
|
||||
|
||||
public TheEntity getTheManyToOne() {
|
||||
return theManyToOne;
|
||||
}
|
||||
|
||||
public void setTheManyToOne(TheEntity theManyToOne) {
|
||||
this.theManyToOne = theManyToOne;
|
||||
}
|
||||
|
||||
public Set<TheEntity> getTheOneToMany() {
|
||||
return theOneToMany;
|
||||
}
|
||||
|
||||
public void setTheOneToMany(Set<TheEntity> theOneToMany) {
|
||||
this.theOneToMany = theOneToMany;
|
||||
}
|
||||
|
||||
public Set<TheEmbeddable> getTheEmbeddableCollection() {
|
||||
return theEmbeddableCollection;
|
||||
}
|
||||
|
||||
public void setTheEmbeddableCollection(Set<TheEmbeddable> theEmbeddableCollection) {
|
||||
this.theEmbeddableCollection = theEmbeddableCollection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
A template for projects wanting to use Hibernate ORM.
|
||||
|
||||
Useful to either:
|
||||
|
||||
1. Bootstrap a new user project
|
||||
2. Bootstrap a test-case project
|
|
@ -0,0 +1,112 @@
|
|||
import org.apache.tools.ant.filters.ReplaceTokens
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
plugins {
|
||||
id 'base'
|
||||
|
||||
// for publishing snapshots
|
||||
id 'maven-publish'
|
||||
id 'org.hibernate.build.maven-repo-auth'
|
||||
|
||||
// publishing to BinTray
|
||||
id "com.jfrog.bintray"
|
||||
id "nu.studer.credentials" version "2.1"
|
||||
}
|
||||
|
||||
// NOTE : Had trouble using the `distribution` plugin, so manually using Jar/Tar tasks
|
||||
|
||||
version = '0.1'
|
||||
|
||||
ext {
|
||||
processedTemplateDir = project.layout.buildDirectory.dir('resources/template')
|
||||
archiveDir = project.layout.buildDirectory.dir('distributions')
|
||||
}
|
||||
|
||||
task processTemplateResources(type:Copy) {
|
||||
inputs.files( 'src/template/resources' )
|
||||
outputs.dir( processedTemplateDir )
|
||||
|
||||
description = 'Copies the template sources into the build dir, performing some replacements'
|
||||
|
||||
from( 'src/template/resources' ) {
|
||||
filter( ReplaceTokens, tokens: [ 'ormVersion' : project.version.toString() ] )
|
||||
}
|
||||
into processedTemplateDir.get().asFile
|
||||
}
|
||||
|
||||
task templateTgz(type:Tar) {
|
||||
description = 'Bundles the template project into a TGZ archive'
|
||||
|
||||
inputs.files( processedTemplateDir )
|
||||
outputs.dir( archiveDir )
|
||||
|
||||
dependsOn project.tasks.processTemplateResources
|
||||
|
||||
compression = Compression.GZIP
|
||||
|
||||
from processedTemplateDir.get().asFile
|
||||
|
||||
destinationDirectory = archiveDir
|
||||
}
|
||||
|
||||
task templateZip(type:Zip) {
|
||||
description = 'Bundles the template project into a Zip archive'
|
||||
|
||||
inputs.files( processedTemplateDir )
|
||||
outputs.dir( archiveDir )
|
||||
|
||||
dependsOn project.tasks.processTemplateResources
|
||||
|
||||
from processedTemplateDir.get().asFile
|
||||
|
||||
destinationDirectory = archiveDir
|
||||
}
|
||||
|
||||
bintray {
|
||||
user = credentials.'personal.bintray.user'
|
||||
key = credentials.'personal.bintray.key'
|
||||
|
||||
filesSpec {
|
||||
from templateTgz
|
||||
from templateZip
|
||||
}
|
||||
|
||||
pkg {
|
||||
userOrg = 'hibernate'
|
||||
repo = 'generic'
|
||||
name = 'orm-project-template'
|
||||
}
|
||||
}
|
||||
|
||||
task assembleDist( dependsOn: [tasks.templateTgz, tasks.templateZip] )
|
||||
task release( dependsOn: tasks.assembleDist )
|
||||
|
||||
tasks.publish {
|
||||
dependsOn tasks.assembleDist
|
||||
}
|
||||
|
||||
tasks.bintrayUpload {
|
||||
dependsOn tasks.assembleDist
|
||||
doFirst {
|
||||
if ( credentials.'personal.bintray.user' == null ) {
|
||||
throw new GradleException( "BinTray user not known, cannot perform upload" );
|
||||
}
|
||||
if ( credentials.'personal.bintray.key' == null ) {
|
||||
throw new GradleException( "BinTray API key not known, cannot perform upload" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( version.toString().endsWith( "-SNAPSHOT" ) ) {
|
||||
tasks.bintrayUpload.enabled = false
|
||||
tasks.release.dependsOn tasks.publish
|
||||
}
|
||||
else {
|
||||
tasks.publish.enabled = false
|
||||
tasks.release.dependsOn tasks.bintrayUpload
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
A template project to help bootstrap a Gradle project with support for Hibernate
|
||||
specific extensions.
|
||||
|
||||
This might be useful for new users wanting to get started as well as a quick way to
|
||||
bootstrap project for test cases (bug reports, etc)
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// ###################################################################################
|
||||
// again, needed to be able to consume `org.hibernate.orm` plugin SNAPSHOTS
|
||||
buildscript {
|
||||
configurations {
|
||||
classpath {
|
||||
resolutionStrategy {
|
||||
cacheChangingModulesFor(0, java.util.concurrent.TimeUnit.SECONDS )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ###################################################################################
|
||||
|
||||
|
||||
plugins {
|
||||
java
|
||||
|
||||
// todo : find a way to inject this version
|
||||
// - this is yet another example of where lazybones
|
||||
// (or proper Gradle build-init feature) would be
|
||||
// incredibly useful. Same with groupId, package-name,
|
||||
// etc.
|
||||
id( "org.hibernate.orm" ) version "@ormVersion@"
|
||||
}
|
||||
|
||||
group = "your.org"
|
||||
version = "the-version"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val ormVersion = "@ormVersion@"
|
||||
val junit5Version = "5.3.1"
|
||||
val h2Version = "1.4.199"
|
||||
|
||||
implementation( "org.hibernate.orm", "hibernate-core", ormVersion )
|
||||
|
||||
testImplementation( "org.hibernate.orm", "hibernate-testing", ormVersion )
|
||||
testImplementation( "org.junit.jupiter", "junit-jupiter-api", junit5Version )
|
||||
testImplementation( "org.junit.jupiter", "junit-jupiter-params", junit5Version )
|
||||
|
||||
testRuntimeOnly( "org.junit.jupiter", "junit-jupiter-engine", junit5Version )
|
||||
testRuntimeOnly( "com.h2database", "h2", h2Version )
|
||||
testRuntimeOnly( "org.jboss.logging", "jboss-logging", "3.3.2.Final" )
|
||||
testRuntimeOnly( "log4j", "log4j", "1.2.17" )
|
||||
}
|
||||
|
||||
hibernate {
|
||||
enhancement {
|
||||
// all false by default
|
||||
lazyInitialization = true
|
||||
dirtyTracking = true
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
|
||||
task( "compile" ) {
|
||||
dependsOn( tasks.compileJava )
|
||||
dependsOn( tasks.compileTestJava )
|
||||
dependsOn( tasks.processResources )
|
||||
dependsOn( tasks.processTestResources )
|
||||
}
|
||||
|
||||
configure<JavaPluginConvention> {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
rootProject.name = "my-hibernate-project"
|
||||
|
||||
// ###################################################################################
|
||||
// A lot of magic to be able to consumer SNAPSHOT versions of the Hibernate ORM plugin...
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
name = "jboss-snapshots-repository"
|
||||
url = uri( "https://repository.jboss.org/nexus/content/repositories/snapshots" )
|
||||
}
|
||||
}
|
||||
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
if ( requested.id.namespace == "org.hibernate"
|
||||
&& requested.id.name == "orm"
|
||||
&& requested.version.orEmpty().endsWith("-SNAPSHOT" ) ) {
|
||||
val notation = "org.hibernate.orm:hibernate-gradle-plugin:${requested.version}"
|
||||
logger.lifecycle( "Swapping SNAPSHOT version of plugin : {}", notation )
|
||||
useModule( notation )
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ###################################################################################
|
|
@ -0,0 +1,38 @@
|
|||
package org.your.domain;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* A simple example entity
|
||||
*/
|
||||
@Entity
|
||||
public class SimpleEntity {
|
||||
@Id
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
private SimpleEntity() {
|
||||
}
|
||||
|
||||
public SimpleEntity(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public SimpleEntity(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package org.your.domain;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static com.arjuna.ats.internal.jdbc.recovery.JDBCXARecovery.PASSWORD;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hibernate.cfg.AvailableSettings.URL;
|
||||
import static org.hibernate.cfg.AvailableSettings.USER;
|
||||
|
||||
/**
|
||||
* Tests for SimpleEntity
|
||||
*/
|
||||
@ServiceRegistry(
|
||||
settings = {
|
||||
// can define settings here, or in `hibernate.properties` file
|
||||
@ServiceRegistry.Setting( name = URL, value = "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=10000" ),
|
||||
@ServiceRegistry.Setting( name = USER, value = "sa" ),
|
||||
@ServiceRegistry.Setting( name = PASSWORD, value = "" )
|
||||
}
|
||||
)
|
||||
@DomainModel( annotatedClasses = SimpleEntity.class )
|
||||
@SessionFactory()
|
||||
public class EntityTests {
|
||||
@Test
|
||||
public void basicTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final SimpleEntity entity = session.createQuery( "from SimpleEntity", SimpleEntity.class ).uniqueResult();
|
||||
assertThat( entity, notNullValue() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void createTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.persist( new SimpleEntity( 1, "the first" ) )
|
||||
);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void dropTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createQuery( "delete SimpleEntity" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.rootLogger=warn, stdout
|
||||
log4j.logger.org.hibernate=info
|
Loading…
Reference in New Issue