HHH-15314 - Hibernate Gradle plugin is not working for Kotlin projects

This commit is contained in:
Steve Ebersole 2022-06-06 20:22:20 -05:00
parent 9b934f6fb0
commit 6ac624a84b
14 changed files with 374 additions and 140 deletions

View File

@ -11,9 +11,6 @@ plugins {
id 'java-gradle-plugin'
id 'com.gradle.plugin-publish' version '0.20.0'
// disable the TestKit tests for the time being as it is having trouble
// which unfortunately also means we do not get any functional testing of the plugin
// id 'com.github.sebersole.testkit-junit5' version '1.2.0'
id 'checkstyle'
// for local publishing
@ -42,6 +39,12 @@ dependencies {
// for Gradle
implementation jakartaLibs.inject
implementation localGroovy()
testImplementation gradleTestKit()
testImplementation testLibs.assertjCore
testImplementation testLibs.junit5Api
testRuntimeOnly testLibs.junit5Engine
}
gradlePlugin {
@ -74,6 +77,10 @@ pluginBundle {
}
}
test {
useJUnitPlatform()
}
// Publish to the Gradle Plugin Portal
tasks.release.dependsOn tasks.publishPlugins

View File

@ -27,12 +27,12 @@ public class HibernateOrmPlugin implements Plugin<Project> {
EnhancementTask.apply( ormDsl, ormDsl.getSourceSetProperty().get(), project );
JpaMetamodelGenerationTask.apply( ormDsl, ormDsl.getSourceSetProperty().get(), project );
project.getDependencies().add(
"implementation",
ormDsl.getHibernateVersionProperty().map( (ormVersion) -> Character.isDigit( ormVersion.charAt( 0 ) )
? "org.hibernate.orm:hibernate-core:" + ormVersion
: null
)
);
// project.getDependencies().add(
// "implementation",
// ormDsl.getHibernateVersionProperty().map( (ormVersion) -> Character.isDigit( ormVersion.charAt( 0 ) )
// ? "org.hibernate.orm:hibernate-core:" + ormVersion
// : null
// )
// );
}
}

View File

@ -44,33 +44,40 @@ public class EnhancementHelper {
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;
}
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
final String className = determineClassName( classesDirFile, changedFile );
final long lastModified = changedFile.lastModified();
enhance( changedFile, className, enhancer, project );
final boolean timestampReset = changedFile.setLastModified( lastModified );
if ( !timestampReset ) {
project.getLogger().debug( "`{}`.setLastModified failed", project.relativePath( changedFile ) );
}
break;
}
case REMOVED: {
// nothing to do
break;
}
default: {
throw new UnsupportedOperationException( "Unexpected ChangeType : " + change.getChangeType().name() );
}
}
break;
}
);
case REMOVED: {
// nothing to do
break;
}
default: {
throw new UnsupportedOperationException( "Unexpected ChangeType : " + change.getChangeType().name() );
}
}
} );
}
private static void enhance(

View File

@ -15,11 +15,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.inject.Inject;
import jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode;
import jakarta.persistence.spi.ClassTransformer;
import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
import javax.sql.DataSource;
import org.gradle.api.DefaultTask;
@ -44,6 +39,12 @@ 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 jakarta.persistence.SharedCacheMode;
import jakarta.persistence.ValidationMode;
import jakarta.persistence.spi.ClassTransformer;
import jakarta.persistence.spi.PersistenceUnitInfo;
import jakarta.persistence.spi.PersistenceUnitTransactionType;
import static org.hibernate.orm.tooling.gradle.HibernateOrmSpec.HIBERNATE;
/**
@ -330,18 +331,6 @@ public class JpaMetamodelGenerationTask extends DefaultTask {
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( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
}
);
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* @author Steve Ebersole
*/
public class Copier {
public static void copyProject(String projectBuildFilePath, Path target) {
final URL resource = Copier.class.getClassLoader().getResource( "projects/" + projectBuildFilePath );
if ( resource == null ) {
throw new RuntimeException( "Unable to locate projectBuildFilePath : " + projectBuildFilePath );
}
try {
final Path sourceProjectDir = Paths.get( resource.toURI() );
copyDirectory( sourceProjectDir.getParent(), target );
}
catch (URISyntaxException e) {
throw new RuntimeException( "Unable to create URI : " + resource, e );
}
}
public static void copyDirectory(Path source, Path target) {
try {
Files.walk( source ).forEach( (sourceItem) -> {
if ( sourceItem.equals( source ) ) {
return;
}
final Path output = target.resolve( source.relativize( sourceItem ) );
try {
Files.copy( sourceItem, output );
}
catch (IOException ioe) {
throw new RuntimeException( "Unable to copy : " + sourceItem.toAbsolutePath(), ioe );
}
} );
}
catch (IOException ioe) {
throw new RuntimeException( "Unable to copy : " + source.toAbsolutePath() );
}
}
}

View File

@ -0,0 +1,180 @@
/*
* 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.nio.file.Path;
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 org.junit.jupiter.api.io.TempDir;
import org.assertj.core.api.Condition;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
/**
* Basic functional tests
*
* @author Steve Ebersole
*/
class HibernateOrmPluginTest {
private static final Condition<TaskOutcome> SUCCESS = new Condition<>(
(taskOutcome) -> taskOutcome == TaskOutcome.SUCCESS,
"task succeeded"
);
private static final Condition<TaskOutcome> UP_TO_DATE = new Condition<>(
(taskOutcome) -> taskOutcome == TaskOutcome.UP_TO_DATE,
"task up-to-date"
);
@Test
public void testEnhancementTask(@TempDir Path projectDir) {
Copier.copyProject( "simple/build.gradle", projectDir );
System.out.println( "First execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "hibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":hibernateEnhance" );
assertThat( task ).isNotNull();
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.SUCCESS );
}
@Test
public void testEnhancementTaskAsFinalizer(@TempDir Path projectDir) {
Copier.copyProject( "simple/build.gradle", projectDir );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "compileJava", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":hibernateEnhance" );
assertThat( task ).isNotNull();
// assertThat( task.getOutcome() ).is( anyOf( SUCCESS, UP_TO_DATE ) );
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.SUCCESS );
}
@Test
@Disabled( "up-to-date checking not working" )
public void testEnhancementTaskUpToDate(@TempDir Path projectDir) {
Copier.copyProject( "simple/build.gradle", projectDir );
{
System.out.println( "First execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "hibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":hibernateEnhance" );
assertThat( task ).isNotNull();
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.SUCCESS );
}
{
System.out.println( "Second execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "hibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":hibernateEnhance" );
assertThat( task ).isNotNull();
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.UP_TO_DATE );
}
}
@Test
public void testJpaMetamodelGen(@TempDir Path projectDir) {
Copier.copyProject( "simple/build.gradle", projectDir );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "generateJpaMetamodel", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":generateJpaMetamodel" );
assertThat( task ).isNotNull();
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.SUCCESS );
}
@Test
// @Disabled( "up-to-date checking not working" )
public void testJpaMetamodelGenUpToDate(@TempDir Path projectDir) {
Copier.copyProject( "simple/build.gradle", projectDir );
{
System.out.println( "First execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "generateJpaMetamodel", "-xhibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":generateJpaMetamodel" );
assertThat( task ).isNotNull();
assertThat( task.getOutcome() ).isEqualTo( TaskOutcome.SUCCESS );
}
{
System.out.println( "Second execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner2 = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "generateJpaMetamodel", "-xhibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result2 = gradleRunner2.build();
final BuildTask task2 = result2.task( ":generateJpaMetamodel" );
assertThat( task2 ).isNotNull();
assertThat( task2.getOutcome() ).isEqualTo( TaskOutcome.UP_TO_DATE );
}
}
@Test
@Disabled( "HHH-15314" )
public void testEnhanceKotlinModel(@TempDir Path projectDir) {
Copier.copyProject( "simple-kotlin/build.gradle", projectDir );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "hibernateEnhance", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask task = result.task( ":hibernateEnhance" );
assertThat( task ).isNotNull();
}
}

View File

@ -0,0 +1,33 @@
/*
* 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 'org.jetbrains.kotlin.jvm' version '1.6.21'
id 'org.hibernate.orm'
}
repositories {
mavenCentral()
maven {
name 'jboss-snapshots-repository'
url 'https://repository.jboss.org/nexus/content/repositories/snapshots'
}
}
dependencies {
implementation 'jakarta.persistence:jakarta.persistence-api:3.0.0'
}
hibernate {
enhancement {
lazyInitialization( true )
dirtyTracking = true
}
jpaMetamodel {
}
}

View File

@ -0,0 +1,9 @@
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
class TheEntity (
@Id
var id: Long? = null,
var name: String? = null,
)

View File

@ -0,0 +1,33 @@
/*
* 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'
}
}
dependencies {
implementation 'jakarta.persistence:jakarta.persistence-api:3.0.0'
}
hibernate {
enhancement {
lazyInitialization( true )
dirtyTracking = true
}
jpaMetamodel {
}
}

View File

@ -1,3 +1,9 @@
/*
* 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.
*/
import jakarta.persistence.Embeddable;
@Embeddable

View File

@ -1,3 +1,9 @@
/*
* 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.
*/
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;

View File

@ -1,91 +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.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 ) )
);
}
}