HHH-18644 - New and improved hibernate-maven-plugin
Signed-off-by: Koen Aers <koen.aers@gmail.com>
This commit is contained in:
parent
817355f8a4
commit
707c3a788f
|
@ -33,6 +33,7 @@ dependencies {
|
|||
implementation "org.apache.maven:maven-compat:3.9.9"
|
||||
implementation "org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18"
|
||||
implementation "org.apache.maven.resolver:maven-resolver-transport-http:1.9.18"
|
||||
implementation "org.slf4j:slf4j-simple:1.7.36"
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
|
|
|
@ -9,6 +9,10 @@ import org.gradle.api.tasks.SourceSet;
|
|||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Plugin for integrating Maven Embedder into the Gradle build to execute
|
||||
* some Maven tasks/goals/mojos.
|
||||
|
@ -29,16 +33,34 @@ public class MavenEmbedderPlugin implements Plugin<Project> {
|
|||
MavenEmbedderConfig.class
|
||||
);
|
||||
|
||||
final Provider<Directory> workingDirectory = project.getLayout().getBuildDirectory().dir("maven-embedder/workspace");
|
||||
|
||||
// add the MavenEmbedderService shared-build-service
|
||||
final Provider<MavenEmbedderService> embedderServiceProvider = sharedServices.registerIfAbsent(
|
||||
"maven-embedder",
|
||||
MavenEmbedderService.class, (spec) -> {
|
||||
spec.getParameters().getProjectVersion().set( project.getVersion().toString() );
|
||||
spec.getParameters().getWorkingDirectory().set( project.getLayout().getProjectDirectory() );
|
||||
spec.getParameters().getWorkingDirectory().set( workingDirectory );
|
||||
spec.getParameters().getMavenLocalDirectory().set( dsl.getLocalRepositoryDirectory() );
|
||||
}
|
||||
);
|
||||
|
||||
project.getTasks().register(
|
||||
"installHibernateCore",
|
||||
RunMavenTask.class,
|
||||
(task) -> {
|
||||
configureInstallHibernateCoreTask(
|
||||
configureInstallTask( configureRunMavenTask( task, embedderServiceProvider ) ) );
|
||||
});
|
||||
|
||||
project.getTasks().register(
|
||||
"installHibernateScanJandex",
|
||||
RunMavenTask.class,
|
||||
(task) -> {
|
||||
configureInstallHibernateScanJandexTask(
|
||||
configureInstallTask( configureRunMavenTask( task, embedderServiceProvider ) ));
|
||||
} );
|
||||
|
||||
// Via the plugin's POM, we tell Maven to generate the descriptors into
|
||||
// `target/generated/sources/plugin-descriptors/META-INF/maven`.
|
||||
// `META-INF/maven` is the relative path we need inside the jar, so we
|
||||
|
@ -46,6 +68,8 @@ public class MavenEmbedderPlugin implements Plugin<Project> {
|
|||
// `target/generated/sources/plugin-descriptors` part.
|
||||
final Provider<Directory> descriptorsDir = project.getLayout().getBuildDirectory().dir( "generated/sources/plugin-descriptors" );
|
||||
|
||||
|
||||
|
||||
// create the "mirror" task which calls the appropriate Maven tasks/goals/mojos behind the scenes using the embedder service
|
||||
final TaskProvider<MavenPluginDescriptorTask> generatePluginDescriptorTask = project.getTasks().register( "generatePluginDescriptor", MavenPluginDescriptorTask.class, (task) -> {
|
||||
task.setGroup( "maven embedder" );
|
||||
|
@ -61,11 +85,160 @@ public class MavenEmbedderPlugin implements Plugin<Project> {
|
|||
final SourceSet mainSourceSet = sourceSets.getByName( "main" );
|
||||
mainSourceSet.getResources().srcDir( task.getDescriptorDirectory() );
|
||||
|
||||
// the hibernate-core jar needs to be present in the local repository
|
||||
// we need compilation to happen before we generate the descriptors
|
||||
task.dependsOn( "compileJava" );
|
||||
task.dependsOn( "prepareWorkspace", "installHibernateCore", "installHibernateScanJandex");
|
||||
} );
|
||||
|
||||
project.getTasks().register(
|
||||
"createMavenWrapper",
|
||||
RunMavenTask.class,
|
||||
(task) -> {
|
||||
configuraCreateMavenWrapperTask(
|
||||
configureRunMavenTask( task, embedderServiceProvider ));
|
||||
} );
|
||||
|
||||
project.getTasks().register(
|
||||
"installHibernateMavenPlugin",
|
||||
RunMavenTask.class,
|
||||
(task) -> {
|
||||
configureInstallHibernateMavenPluginTask(
|
||||
configureInstallTask(
|
||||
configureRunMavenTask( task, embedderServiceProvider )));
|
||||
} );
|
||||
|
||||
project.getTasks().register(
|
||||
"integrationTest",
|
||||
RunMavenTask.class,
|
||||
(task) -> {
|
||||
configureIntegrationTestTask(
|
||||
configureRunMavenTask( task, embedderServiceProvider ));
|
||||
} );
|
||||
|
||||
// we need the descriptor generation to happen before we jar
|
||||
project.getTasks().named( "jar", (jarTask) -> jarTask.dependsOn( generatePluginDescriptorTask ) );
|
||||
project.getTasks().named( "check" , (checkTask) -> checkTask.dependsOn( "integrationTest", generatePluginDescriptorTask ) );
|
||||
}
|
||||
|
||||
private void configureInstallHibernateMavenPluginTask(RunMavenTask task) {
|
||||
List<String> arguments = new ArrayList<String>(task.getArguments().get());
|
||||
arguments.add("-Dfile=" + getHibernateMavenPluginArtifactFilePath( task.getProject() ));
|
||||
arguments.add("-DartifactId=hibernate-maven-plugin");
|
||||
arguments.add( "-DpomFile=" + getHibernateMavenPluginPomFilePath( task.getProject() ) );
|
||||
task.getArguments().set( arguments );
|
||||
task.dependsOn("jar", "generatePluginDescriptor");
|
||||
}
|
||||
|
||||
private void configureInstallHibernateCoreTask(RunMavenTask task) {
|
||||
List<String> arguments = new ArrayList<String>(task.getArguments().get());
|
||||
arguments.add("-Dfile=" + getHibernateCoreArtifactFilePath( task.getProject() ));
|
||||
arguments.add("-DartifactId=hibernate-core");
|
||||
arguments.add( "-DpomFile=" + getHibernateCorePomFilePath( task.getProject() ) );
|
||||
task.getArguments().set( arguments );
|
||||
task.dependsOn(":hibernate-core:generatePomFileForPublishedArtifactsPublication", ":hibernate-core:jar");
|
||||
}
|
||||
|
||||
private void configureInstallHibernateScanJandexTask(RunMavenTask task) {
|
||||
List<String> arguments = new ArrayList<String>(task.getArguments().get());
|
||||
arguments.add("-Dfile=" + getHibernateScanJandexArtifactFilePath( task.getProject() ));
|
||||
arguments.add("-DartifactId=hibernate-scan-jandex");
|
||||
task.getArguments().set( arguments );
|
||||
task.dependsOn(":hibernate-scan-jandex:jar");
|
||||
}
|
||||
|
||||
private void configureIntegrationTestTask(RunMavenTask task) {
|
||||
task.getGoals().set( "invoker:run" );
|
||||
task.dependsOn("createMavenWrapper", "installHibernateMavenPlugin");
|
||||
}
|
||||
|
||||
private void configuraCreateMavenWrapperTask(RunMavenTask task) {
|
||||
task.getGoals().set("wrapper:wrapper");
|
||||
task.getArguments().set( List.of("-f" + getIntegrationTestFolderPath( task.getProject() ) ));
|
||||
task.dependsOn( "prepareWorkspace" );
|
||||
}
|
||||
|
||||
private String getHibernateMavenPluginPomFilePath(Project project) {
|
||||
return project
|
||||
.getLayout()
|
||||
.getBuildDirectory()
|
||||
.file( "publications/publishedArtifacts/pom-default.xml")
|
||||
.get()
|
||||
.getAsFile()
|
||||
.getAbsolutePath();
|
||||
}
|
||||
|
||||
private String getHibernateMavenPluginArtifactFilePath(Project project) {
|
||||
final String artifactName = "hibernate-maven-plugin-" + project.getVersion() + ".jar";
|
||||
final File libsFolder = project.getLayout().getBuildDirectory().dir("libs" ).get().getAsFile();
|
||||
return new File(libsFolder, artifactName).getAbsolutePath();
|
||||
}
|
||||
|
||||
private RunMavenTask configureRunMavenTask(
|
||||
RunMavenTask task,
|
||||
Provider<MavenEmbedderService> embedderServiceProvider) {
|
||||
task.setGroup( "maven embedder" );
|
||||
task.getMavenEmbedderService().set( embedderServiceProvider );
|
||||
task.usesService( embedderServiceProvider );
|
||||
return task;
|
||||
}
|
||||
|
||||
private Directory getWorkingDirectory(Project project) {
|
||||
return project.getLayout().getBuildDirectory().dir("maven-embedder/workspace").get();
|
||||
}
|
||||
|
||||
private String getIntegrationTestFolderPath(Project project) {
|
||||
return getWorkingDirectory( project).dir( "src/it/enhance" ).getAsFile().getAbsolutePath();
|
||||
}
|
||||
|
||||
private RunMavenTask configureInstallTask(RunMavenTask task) {
|
||||
task.getGoals().set( "install:install-file" );
|
||||
ArrayList<String> arguments = new ArrayList<String>();
|
||||
arguments.add("-DgroupId=" + task.getProject().getGroup().toString());
|
||||
arguments.add("-Dversion=" + task.getProject().getVersion());
|
||||
arguments.add("-Dpackaging=jar");
|
||||
task.getArguments().set( arguments );
|
||||
return task;
|
||||
}
|
||||
|
||||
private String getHibernateCoreArtifactFilePath(Project project) {
|
||||
final String artifactName = "hibernate-core-" + project.getVersion() + ".jar";
|
||||
final File hibernateCoreLibsFolder = getHibernateCoreBuildDirectory( project )
|
||||
.dir( "libs" )
|
||||
.getAsFile();
|
||||
return new File(hibernateCoreLibsFolder, artifactName).getAbsolutePath();
|
||||
}
|
||||
|
||||
private String getHibernateCorePomFilePath(Project project) {
|
||||
return getHibernateCoreBuildDirectory( project )
|
||||
.file( "publications/publishedArtifacts/pom-default.xml" )
|
||||
.getAsFile()
|
||||
.getAbsolutePath();
|
||||
}
|
||||
|
||||
private String getHibernateScanJandexArtifactFilePath(Project project) {
|
||||
final String artifactName = "hibernate-scan-jandex-" + project.getVersion() + ".jar";
|
||||
final File hibernateScanJandexLibsFolder = getHibernateScanJandexBuildDirectory( project )
|
||||
.dir( "libs" )
|
||||
.getAsFile();
|
||||
return new File(hibernateScanJandexLibsFolder, artifactName).getAbsolutePath();
|
||||
}
|
||||
|
||||
private Directory getHibernateCoreBuildDirectory(Project project) {
|
||||
return project
|
||||
.getRootProject()
|
||||
.project( "hibernate-core" )
|
||||
.getLayout()
|
||||
.getBuildDirectory()
|
||||
.get();
|
||||
}
|
||||
|
||||
private Directory getHibernateScanJandexBuildDirectory(Project project) {
|
||||
return project
|
||||
.getRootProject()
|
||||
.project( "hibernate-scan-jandex" )
|
||||
.getLayout()
|
||||
.getBuildDirectory()
|
||||
.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.hibernate.build.maven.embedder;
|
||||
|
||||
import org.apache.maven.cli.MavenCli;
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.file.Directory;
|
||||
import org.gradle.api.file.DirectoryProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
|
@ -37,7 +38,7 @@ public abstract class MavenEmbedderService implements BuildService<MavenEmbedder
|
|||
Collections.addAll( cml, tasksAndArgs );
|
||||
|
||||
final Directory mavenLocalDirectory = getParameters().getMavenLocalDirectory().get();
|
||||
cml.add( "-Dmaven.repo.local=\"" + mavenLocalDirectory.getAsFile().getAbsolutePath() + "\"" );
|
||||
cml.add( "-Dmaven.repo.local=" + mavenLocalDirectory.getAsFile().getAbsolutePath() );
|
||||
cml.add( "-Dorm.project.version=" + getParameters().getProjectVersion().get() );
|
||||
|
||||
final Directory workingDirectory = getParameters().getWorkingDirectory().get();
|
||||
|
@ -46,6 +47,12 @@ public abstract class MavenEmbedderService implements BuildService<MavenEmbedder
|
|||
// todo : consider bridging Maven out/err to Gradle logging
|
||||
|
||||
final int resultCode = embedder.doMain( cml.toArray(new String[0]), workingDirectoryPath, System.out, System.err );
|
||||
// todo : do something with result-code
|
||||
if (resultCode != 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : tasksAndArgs) {
|
||||
sb.append( s );
|
||||
}
|
||||
throw new GradleException("Maven execution has failed: " + sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,9 +28,11 @@ public abstract class MavenPluginDescriptorTask extends DefaultTask {
|
|||
|
||||
@TaskAction
|
||||
public void generateDescriptor() {
|
||||
getMavenEmbedderService().get().execute( "plugin:descriptor" );
|
||||
// todo : anything else? e.g.
|
||||
//getMavenEmbedderService().get().execute( "plugin:addPluginArtifactMetadata" );
|
||||
//getMavenEmbedderService().get().execute( "plugin:helpmojo" );
|
||||
performDescriptorGeneration();
|
||||
}
|
||||
|
||||
private void performDescriptorGeneration() {
|
||||
getMavenEmbedderService().get().execute( "plugin:descriptor" );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package org.hibernate.build.maven.embedder;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.provider.ListProperty;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.services.ServiceReference;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class RunMavenTask extends DefaultTask {
|
||||
|
||||
@ServiceReference
|
||||
abstract Property<MavenEmbedderService> getMavenEmbedderService();
|
||||
|
||||
@Input
|
||||
abstract Property<String> getGoals();
|
||||
|
||||
@Input
|
||||
abstract ListProperty<String> getArguments();
|
||||
|
||||
@TaskAction
|
||||
public void run() {
|
||||
getMavenEmbedderService().get().execute( constructTaskAndArgs() );
|
||||
}
|
||||
|
||||
private String[] constructTaskAndArgs() {
|
||||
List<String> args = new ArrayList<String>();
|
||||
args.add( getGoals().get() );
|
||||
args.addAll( getArguments().get() );
|
||||
return args.toArray(new String[0]);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.hibernate.build.maven.embedder.logging;
|
||||
|
||||
import org.apache.maven.cli.logging.impl.Slf4jSimpleConfiguration;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.impl.MavenSlf4jSimpleFriend;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class Slf4jConfiguration extends Slf4jSimpleConfiguration {
|
||||
@Override
|
||||
public void activate() {
|
||||
resetLoggerFactory();
|
||||
initMavenSlf4jSimpleFriend();
|
||||
}
|
||||
|
||||
private void resetLoggerFactory() {
|
||||
try {
|
||||
Method m = LoggerFactory.class.getDeclaredMethod("reset", new Class[]{});
|
||||
m.setAccessible(true);
|
||||
m.invoke(null);
|
||||
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void initMavenSlf4jSimpleFriend() {
|
||||
MavenSlf4jSimpleFriend.init();
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext org.hibernate.build.maven.embedder.logging.Slf4jConfiguration
|
|
@ -1,6 +1,6 @@
|
|||
description = 'Maven plugin to integrate aspects of Hibernate into your build.'
|
||||
|
||||
//apply from: rootProject.file( 'gradle/published-java-module.gradle' )
|
||||
apply from: rootProject.file( 'gradle/publishing-pom.gradle' )
|
||||
apply from: rootProject.file( 'gradle/java-module.gradle' )
|
||||
|
||||
apply plugin: 'org.hibernate.build.maven-embedder'
|
||||
|
@ -18,4 +18,100 @@ dependencies {
|
|||
implementation "org.apache.maven:maven-plugin-api:3.6.3"
|
||||
implementation "org.apache.maven.plugin-tools:maven-plugin-annotations:3.6.0"
|
||||
implementation "org.apache.maven:maven-project:2.2.1"
|
||||
}
|
||||
implementation "org.apache.maven.shared:file-management:3.1.0"
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
publishedArtifacts(MavenPublication) {
|
||||
from components.java
|
||||
pom.withXml {
|
||||
asNode()
|
||||
.version
|
||||
.plus {
|
||||
packaging('maven-plugin')
|
||||
}
|
||||
asNode()
|
||||
.dependencies
|
||||
.dependency
|
||||
.findAll { dependency ->
|
||||
dependency.groupId.text().startsWith('org.apache.maven')
|
||||
}
|
||||
.each { dependency ->
|
||||
if (dependency.groupId.text().startsWith('org.apache.maven.shared')) {
|
||||
dependency.scope*.value = 'compile'
|
||||
} else {
|
||||
dependency.scope*.value = 'provided'
|
||||
}
|
||||
}
|
||||
asNode()
|
||||
.dependencies
|
||||
.dependency
|
||||
.findAll { dependency ->
|
||||
dependency.groupId.text().startsWith('org.hibernate.orm')
|
||||
}
|
||||
.each { dependency ->
|
||||
dependency.scope*.value = 'compile'
|
||||
}
|
||||
asNode()
|
||||
.dependencies
|
||||
.plus {
|
||||
def plugins = build().appendNode('plugins')
|
||||
def pluginPlugin = plugins.appendNode('plugin')
|
||||
pluginPlugin.appendNode('groupId', 'org.apache.maven.plugins')
|
||||
pluginPlugin.appendNode('artifactId', 'maven-plugin-plugin')
|
||||
pluginPlugin.appendNode('version', '3.15.0')
|
||||
def pluginConfiguration = pluginPlugin.appendNode('configuration')
|
||||
pluginConfiguration.appendNode('goalPrefix', 'plugin')
|
||||
pluginConfiguration.appendNode('outputDirectory', layout.buildDirectory.dir('generated/sources/plugin-descriptors/META-INF/maven').get().getAsFile().getAbsolutePath() )
|
||||
def invokerPlugin = plugins.appendNode('plugin');
|
||||
invokerPlugin.appendNode('groupId', 'org.apache.maven.plugins')
|
||||
invokerPlugin.appendNode('artifactId', 'maven-invoker-plugin')
|
||||
invokerPlugin.appendNode('version', '3.8.0')
|
||||
def invokerConfiguration = invokerPlugin.appendNode('configuration');
|
||||
invokerConfiguration.appendNode('debug', 'true');
|
||||
invokerConfiguration.appendNode('mavenExecutable', 'mvnw');
|
||||
def scriptVariables = invokerConfiguration.appendNode('scriptVariables');
|
||||
scriptVariables.appendNode('hibernateCoreJarPath', layout.buildDirectory.file('maven-embedder/maven-local/org/hibernate/orm/hibernate-core/' + project.version + '/hibernate-core-' + project.version + '.jar').get().getAsFile().getAbsolutePath())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Following tasks need to be performed:
|
||||
// 1. Compile the Java classes
|
||||
// 2. Copy the source tree to the working directory
|
||||
// 3. Copy the compiled Java classes to the working directory
|
||||
// 4. Install the 'hibernate-core' dependency in the local Maven repo
|
||||
// 5. Install the 'hibernate-scan-jandex' dependency in the local Maven repo
|
||||
// 6. Generate the pom.xml file for the Maven plugin
|
||||
// 7. Generate the Maven plugin descriptor
|
||||
// 8. Create the jar for the Maven plugin
|
||||
// 9. Install the Maven plugin descriptor in the local Maven repo
|
||||
// 10. Run the integration tests
|
||||
|
||||
// Prepare the working directory
|
||||
tasks.register('prepareWorkspace', Copy) {
|
||||
into('target/maven-embedder/workspace')
|
||||
// copy the plugin pom
|
||||
with( copySpec {
|
||||
from('target/publications/publishedArtifacts/pom-default.xml')
|
||||
rename('pom-default.xml', 'pom.xml')
|
||||
dependsOn('generatePomFileForPublishedArtifactsPublication')
|
||||
})
|
||||
// copy the compiled java classes
|
||||
into('target/classes') {
|
||||
with( copySpec {
|
||||
from('target/classes/java/main')
|
||||
dependsOn('compileJava')
|
||||
})
|
||||
}
|
||||
// copy the integration tests
|
||||
into('src/it') {
|
||||
with( copySpec {
|
||||
from('src/it')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.hibernate.orm.tooling.maven</groupId>
|
||||
<artifactId>enhance-test</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>7.0.0.Beta1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jakarta.persistence</groupId>
|
||||
<artifactId>jakarta.persistence-api</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.hibernate.orm</groupId>
|
||||
<artifactId>hibernate-maven-plugin</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>enhance</id>
|
||||
<phase>process-classes</phase>
|
||||
<configuration>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/classes</directory>
|
||||
<excludes>
|
||||
<exclude>**/Baz.class</exclude>
|
||||
</excludes>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<enableLazyInitialization>true</enableLazyInitialization>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>enhance</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,18 @@
|
|||
package org.foo;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Bar {
|
||||
|
||||
private String foo;
|
||||
|
||||
String getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(String f) {
|
||||
foo = f;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package org.foo;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
@Entity
|
||||
public class Baz {
|
||||
|
||||
private String foo;
|
||||
|
||||
String getFoo() {
|
||||
return foo;
|
||||
}
|
||||
|
||||
public void setFoo(String f) {
|
||||
foo = f;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.foo;
|
||||
|
||||
public class Foo {
|
||||
|
||||
private Bar bar;
|
||||
|
||||
Bar getBar() {
|
||||
return bar;
|
||||
}
|
||||
|
||||
public void setBar(Bar b) {
|
||||
bar = b;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
File classesFolder = new File(basedir, "target/classes");
|
||||
if (!classesFolder.exists()) {
|
||||
throw new FileNotFoundException("Folder should exist: " + classesFolder);
|
||||
}
|
||||
|
||||
File hibCoreJar = new File(localRepositoryPath, hibernateCoreJarPath);
|
||||
if (!hibCoreJar.exists()) {
|
||||
throw new FileNotFoundException("Hibernate Core jar should exist: " + hibCoreJar);
|
||||
}
|
||||
|
||||
URL[] urls = new URL[2];
|
||||
urls[0] = classesFolder.toURI().toURL();
|
||||
urls[1] = hibCoreJar.toURI().toURL();
|
||||
|
||||
ClassLoader loader = new URLClassLoader(urls);
|
||||
|
||||
Class barClass = loader.loadClass("org.foo.Bar");
|
||||
if (barClass == null) {
|
||||
throw new ClassNotFoundException("Class 'org.foo.Bar' should be loaded");
|
||||
}
|
||||
Class fooClass = loader.loadClass("org.foo.Foo");
|
||||
if (fooClass == null) {
|
||||
throw new FileNotFoundException("Class 'org.foo.Foo' should be loaded");
|
||||
}
|
||||
Class bazClass = loader.loadClass("org.foo.Baz");
|
||||
if (bazClass == null) {
|
||||
throw new FileNotFoundException("Class 'org.foo.Baz' should be loaded");
|
||||
}
|
||||
|
||||
Object m = barClass.getMethod("$$_hibernate_getEntityInstance", new Class[]{});
|
||||
if (m == null) {
|
||||
throw new NoSuchMethodException("Method 'org.foo.Baz#$$_hibernate_getEntityInstance' does not exist");
|
||||
} else {
|
||||
System.out.println("Class '" + barClass.getName() + "' was enhanced succesfully!");
|
||||
}
|
||||
|
||||
try {
|
||||
m = fooClass.getMethod("$$_hibernate_getEntityInstance", new Class[]{});
|
||||
// we need to fail here because the class 'org.foo.Foo' should not be enhanced
|
||||
throw new RuntimeException("Class '" + fooClass + "' should not be enhanced!");
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.out.println("Class '" + fooClass.getName() + "' was correctly left unchanged.");
|
||||
}
|
||||
|
||||
try {
|
||||
m = bazClass.getMethod("$$_hibernate_getEntityInstance", new Class[]{});
|
||||
// we need to fail here because the class 'org.foo.Baz' should not be enhanced
|
||||
throw new RuntimeException("Class '" + bazClass + "' should not be enhanced!");
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.out.println("Class '" + bazClass.getName() + "' was correctly left unchanged.");
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.tooling.maven;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedClass;
|
||||
import org.hibernate.bytecode.enhance.spi.UnloadedField;
|
||||
|
||||
public class EnhancementContext extends DefaultEnhancementContext {
|
||||
|
||||
private ClassLoader classLoader = null;
|
||||
private boolean enableAssociationManagement = false;
|
||||
private boolean enableDirtyTracking = false;
|
||||
private boolean enableLazyInitialization = false;
|
||||
private boolean enableExtendedEnhancement = false;
|
||||
|
||||
public EnhancementContext(
|
||||
ClassLoader classLoader,
|
||||
boolean enableAssociationManagement,
|
||||
boolean enableDirtyTracking,
|
||||
boolean enableLazyInitialization,
|
||||
boolean enableExtendedEnhancement) {
|
||||
this.classLoader = classLoader;
|
||||
this.enableAssociationManagement = enableAssociationManagement;
|
||||
this.enableDirtyTracking = enableDirtyTracking;
|
||||
this.enableLazyInitialization = enableLazyInitialization;
|
||||
this.enableExtendedEnhancement = enableExtendedEnhancement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader getLoadingClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doBiDirectionalAssociationManagement(UnloadedField field) {
|
||||
return enableAssociationManagement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doDirtyCheckingInline(UnloadedClass classDescriptor) {
|
||||
return enableDirtyTracking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLazyLoadableAttributes(UnloadedClass classDescriptor) {
|
||||
return enableLazyInitialization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLazyLoadable(UnloadedField field) {
|
||||
return enableLazyInitialization;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doExtendedEnhancement(UnloadedClass classDescriptor) {
|
||||
return enableExtendedEnhancement;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.tooling.maven;
|
||||
|
||||
import org.apache.maven.plugin.AbstractMojo;
|
||||
import org.apache.maven.plugins.annotations.LifecyclePhase;
|
||||
import org.apache.maven.plugins.annotations.Mojo;
|
||||
import org.apache.maven.plugins.annotations.Parameter;
|
||||
import org.apache.maven.shared.model.fileset.FileSet;
|
||||
import org.apache.maven.shared.model.fileset.util.FileSetManager;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementException;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.hibernate.bytecode.internal.BytecodeProviderInitiator;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Maven mojo for performing build-time enhancement of entity objects.
|
||||
*/
|
||||
@Mojo(name = "enhance", defaultPhase = LifecyclePhase.PROCESS_CLASSES)
|
||||
public class HibernateEnhancerMojo extends AbstractMojo {
|
||||
|
||||
final private List<File> sourceSet = new ArrayList<File>();
|
||||
private Enhancer enhancer;
|
||||
|
||||
@Parameter
|
||||
private FileSet[] fileSets;
|
||||
|
||||
@Parameter(
|
||||
defaultValue = "${project.build.directory}/classes",
|
||||
readonly = true,
|
||||
required = true)
|
||||
private File classesDirectory;
|
||||
|
||||
@Parameter(
|
||||
defaultValue = "false",
|
||||
readonly = true,
|
||||
required = true)
|
||||
private boolean enableAssociationManagement;
|
||||
|
||||
@Parameter(
|
||||
defaultValue = "false",
|
||||
readonly = true,
|
||||
required = true)
|
||||
private boolean enableDirtyTracking;
|
||||
|
||||
@Parameter(
|
||||
defaultValue = "false",
|
||||
readonly = true,
|
||||
required = true)
|
||||
private boolean enableLazyInitialization;
|
||||
|
||||
@Parameter(
|
||||
defaultValue = "false",
|
||||
readonly = true,
|
||||
required = true)
|
||||
private boolean enableExtendedEnhancement;
|
||||
|
||||
public void execute() {
|
||||
getLog().debug(STARTING_EXECUTION_OF_ENHANCE_MOJO);
|
||||
processParameters();
|
||||
assembleSourceSet();
|
||||
createEnhancer();
|
||||
discoverTypes();
|
||||
performEnhancement();
|
||||
getLog().debug(ENDING_EXECUTION_OF_ENHANCE_MOJO);
|
||||
}
|
||||
|
||||
private void processParameters() {
|
||||
if (!enableLazyInitialization) {
|
||||
getLog().warn(ENABLE_LAZY_INITIALIZATION_DEPRECATED);
|
||||
}
|
||||
if (!enableDirtyTracking) {
|
||||
getLog().warn(ENABLE_DIRTY_TRACKING_DEPRECATED);
|
||||
}
|
||||
if (fileSets == null) {
|
||||
fileSets = new FileSet[1];
|
||||
fileSets[0] = new FileSet();
|
||||
fileSets[0].setDirectory(classesDirectory.getAbsolutePath());
|
||||
getLog().debug(ADDED_DEFAULT_FILESET_WITH_BASE_DIRECTORY.formatted(fileSets[0].getDirectory()));
|
||||
}
|
||||
}
|
||||
|
||||
private void assembleSourceSet() {
|
||||
getLog().debug(STARTING_ASSEMBLY_OF_SOURCESET);
|
||||
for (FileSet fileSet : fileSets) {
|
||||
addFileSetToSourceSet(fileSet);
|
||||
}
|
||||
getLog().debug(ENDING_ASSEMBLY_OF_SOURCESET);
|
||||
}
|
||||
|
||||
private void addFileSetToSourceSet(FileSet fileSet) {
|
||||
getLog().debug(PROCESSING_FILE_SET);
|
||||
String directory = fileSet.getDirectory();
|
||||
FileSetManager fileSetManager = new FileSetManager();
|
||||
File baseDir = classesDirectory;
|
||||
if (directory != null && classesDirectory != null) {
|
||||
baseDir = new File(directory);
|
||||
}
|
||||
getLog().debug(USING_BASE_DIRECTORY.formatted(baseDir));
|
||||
for (String fileName : fileSetManager.getIncludedFiles(fileSet)) {
|
||||
File candidateFile = new File(baseDir, fileName);
|
||||
if (fileName.endsWith(".class")) {
|
||||
sourceSet.add(candidateFile);
|
||||
getLog().info(ADDED_FILE_TO_SOURCE_SET.formatted(candidateFile));
|
||||
}
|
||||
else {
|
||||
getLog().debug(SKIPPING_NON_CLASS_FILE.formatted(candidateFile));
|
||||
}
|
||||
}
|
||||
getLog().debug(FILESET_PROCESSED_SUCCESFULLY);
|
||||
}
|
||||
|
||||
private ClassLoader createClassLoader() {
|
||||
getLog().debug(CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)) ;
|
||||
List<URL> urls = new ArrayList<>();
|
||||
try {
|
||||
urls.add(classesDirectory.toURI().toURL());
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
getLog().error(UNEXPECTED_ERROR_WHILE_CONSTRUCTING_CLASSLOADER, e);
|
||||
}
|
||||
return new URLClassLoader(
|
||||
urls.toArray(new URL[0]),
|
||||
Enhancer.class.getClassLoader());
|
||||
}
|
||||
|
||||
private EnhancementContext createEnhancementContext() {
|
||||
getLog().debug(CREATE_ENHANCEMENT_CONTEXT) ;
|
||||
return new EnhancementContext(
|
||||
createClassLoader(),
|
||||
enableAssociationManagement,
|
||||
enableDirtyTracking,
|
||||
enableLazyInitialization,
|
||||
enableExtendedEnhancement);
|
||||
}
|
||||
|
||||
private void createEnhancer() {
|
||||
getLog().debug(CREATE_BYTECODE_ENHANCER) ;
|
||||
enhancer = BytecodeProviderInitiator
|
||||
.buildDefaultBytecodeProvider()
|
||||
.getEnhancer(createEnhancementContext());
|
||||
}
|
||||
|
||||
private void discoverTypes() {
|
||||
getLog().debug(STARTING_TYPE_DISCOVERY) ;
|
||||
for (File classFile : sourceSet) {
|
||||
discoverTypesForClass(classFile);
|
||||
}
|
||||
getLog().debug(ENDING_TYPE_DISCOVERY) ;
|
||||
}
|
||||
|
||||
private void discoverTypesForClass(File classFile) {
|
||||
getLog().debug(TRYING_TO_DISCOVER_TYPES_FOR_CLASS_FILE.formatted(classFile));
|
||||
try {
|
||||
enhancer.discoverTypes(
|
||||
determineClassName(classFile),
|
||||
Files.readAllBytes( classFile.toPath()));
|
||||
getLog().info(SUCCESFULLY_DISCOVERED_TYPES_FOR_CLASS_FILE.formatted(classFile));
|
||||
}
|
||||
catch (IOException e) {
|
||||
getLog().error(UNABLE_TO_DISCOVER_TYPES_FOR_CLASS_FILE.formatted(classFile), e);
|
||||
}
|
||||
}
|
||||
|
||||
private String determineClassName(File classFile) {
|
||||
getLog().debug(DETERMINE_CLASS_NAME_FOR_FILE.formatted(classFile));
|
||||
String classFilePath = classFile.getAbsolutePath();
|
||||
String classesDirectoryPath = classesDirectory.getAbsolutePath();
|
||||
return classFilePath.substring(
|
||||
classesDirectoryPath.length() + 1,
|
||||
classFilePath.length() - ".class".length())
|
||||
.replace(File.separatorChar, '.');
|
||||
}
|
||||
|
||||
private void performEnhancement() {
|
||||
getLog().debug(STARTING_CLASS_ENHANCEMENT) ;
|
||||
for (File classFile : sourceSet) {
|
||||
long lastModified = classFile.lastModified();
|
||||
enhanceClass(classFile);
|
||||
final boolean timestampReset = classFile.setLastModified( lastModified );
|
||||
if ( !timestampReset ) {
|
||||
getLog().debug(SETTING_LASTMODIFIED_FAILED_FOR_CLASS_FILE.formatted(classFile));
|
||||
}
|
||||
}
|
||||
getLog().debug(ENDING_CLASS_ENHANCEMENT) ;
|
||||
}
|
||||
|
||||
private void enhanceClass(File classFile) {
|
||||
getLog().debug(TRYING_TO_ENHANCE_CLASS_FILE.formatted(classFile));
|
||||
try {
|
||||
byte[] newBytes = enhancer.enhance(
|
||||
determineClassName(classFile),
|
||||
Files.readAllBytes(classFile.toPath()));
|
||||
if (newBytes != null) {
|
||||
writeByteCodeToFile(newBytes, classFile);
|
||||
getLog().info(SUCCESFULLY_ENHANCED_CLASS_FILE.formatted(classFile));
|
||||
}
|
||||
else {
|
||||
getLog().info(SKIPPING_FILE.formatted(classFile));
|
||||
}
|
||||
}
|
||||
catch (EnhancementException | IOException e) {
|
||||
getLog().error(ERROR_WHILE_ENHANCING_CLASS_FILE.formatted(classFile), e);;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeByteCodeToFile(byte[] bytes, File file) {
|
||||
getLog().debug(WRITING_BYTE_CODE_TO_FILE.formatted(file));
|
||||
if (clearFile(file)) {
|
||||
try {
|
||||
Files.write( file.toPath(), bytes);
|
||||
getLog().debug(AMOUNT_BYTES_WRITTEN_TO_FILE.formatted(bytes.length, file));
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
getLog().error(ERROR_OPENING_FILE_FOR_WRITING.formatted(file), e );
|
||||
}
|
||||
catch (IOException e) {
|
||||
getLog().error(ERROR_WRITING_BYTES_TO_FILE.formatted(file), e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean clearFile(File file) {
|
||||
getLog().debug(TRYING_TO_CLEAR_FILE.formatted(file));
|
||||
boolean success = false;
|
||||
if ( file.delete() ) {
|
||||
try {
|
||||
if ( !file.createNewFile() ) {
|
||||
getLog().error(UNABLE_TO_CREATE_FILE.formatted(file));
|
||||
}
|
||||
else {
|
||||
getLog().info(SUCCESFULLY_CLEARED_FILE.formatted(file));
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
getLog().warn(PROBLEM_CLEARING_FILE.formatted(file), e);
|
||||
}
|
||||
}
|
||||
else {
|
||||
getLog().error(UNABLE_TO_DELETE_FILE.formatted(file));
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// info messages
|
||||
static final String SUCCESFULLY_CLEARED_FILE = "Succesfully cleared the contents of file: %s";
|
||||
static final String SUCCESFULLY_ENHANCED_CLASS_FILE = "Succesfully enhanced class file: %s";
|
||||
static final String SKIPPING_FILE = "Skipping file: %s";
|
||||
static final String SUCCESFULLY_DISCOVERED_TYPES_FOR_CLASS_FILE = "Succesfully discovered types for classes in file: %s";
|
||||
static final String ADDED_FILE_TO_SOURCE_SET = "Added file to source set: %s";
|
||||
|
||||
// warning messages
|
||||
static final String PROBLEM_CLEARING_FILE = "Problem clearing file for writing out enhancements [ %s ]";
|
||||
static final String ENABLE_LAZY_INITIALIZATION_DEPRECATED = "The 'enableLazyInitialization' configuration is deprecated and will be removed. Set the value to 'true' to get rid of this warning";
|
||||
static final String ENABLE_DIRTY_TRACKING_DEPRECATED = "The 'enableDirtyTracking' configuration is deprecated and will be removed. Set the value to 'true' to get rid of this warning";
|
||||
|
||||
// error messages
|
||||
static final String UNABLE_TO_CREATE_FILE = "Unable to create file: %s";
|
||||
static final String UNABLE_TO_DELETE_FILE = "Unable to delete file: %s";
|
||||
static final String ERROR_WRITING_BYTES_TO_FILE = "Error writing bytes to file : %s";
|
||||
static final String ERROR_OPENING_FILE_FOR_WRITING = "Error opening file for writing : %s";
|
||||
static final String ERROR_WHILE_ENHANCING_CLASS_FILE = "An exception occurred while trying to class file: %s";
|
||||
static final String UNABLE_TO_DISCOVER_TYPES_FOR_CLASS_FILE = "Unable to discover types for classes in file: %s";
|
||||
static final String UNEXPECTED_ERROR_WHILE_CONSTRUCTING_CLASSLOADER = "An unexpected error occurred while constructing the classloader";
|
||||
|
||||
// debug messages
|
||||
static final String TRYING_TO_CLEAR_FILE = "Trying to clear the contents of file: %s";
|
||||
static final String AMOUNT_BYTES_WRITTEN_TO_FILE = "%s bytes were succesfully written to file: %s";
|
||||
static final String WRITING_BYTE_CODE_TO_FILE = "Writing byte code to file: %s";
|
||||
static final String DETERMINE_CLASS_NAME_FOR_FILE = "Determining class name for file: %s";
|
||||
static final String TRYING_TO_ENHANCE_CLASS_FILE = "Trying to enhance class file: %s";
|
||||
static final String STARTING_CLASS_ENHANCEMENT = "Starting class enhancement";
|
||||
static final String SETTING_LASTMODIFIED_FAILED_FOR_CLASS_FILE = "Setting lastModified failed for class file: %s";
|
||||
static final String ENDING_CLASS_ENHANCEMENT = "Ending class enhancement";
|
||||
static final String TRYING_TO_DISCOVER_TYPES_FOR_CLASS_FILE = "Trying to discover types for classes in file: %s";
|
||||
static final String STARTING_TYPE_DISCOVERY = "Starting type discovery";
|
||||
static final String ENDING_TYPE_DISCOVERY = "Ending type discovery";
|
||||
static final String CREATE_BYTECODE_ENHANCER = "Creating bytecode enhancer";
|
||||
static final String CREATE_ENHANCEMENT_CONTEXT = "Creating enhancement context";
|
||||
static final String CREATE_URL_CLASSLOADER_FOR_FOLDER = "Creating URL ClassLoader for folder: %s";
|
||||
static final String PROCESSING_FILE_SET = "Processing FileSet";
|
||||
static final String USING_BASE_DIRECTORY = "Using base directory: %s";
|
||||
static final String SKIPPING_NON_CLASS_FILE = "Skipping non '.class' file: %s";
|
||||
static final String FILESET_PROCESSED_SUCCESFULLY = "FileSet was processed succesfully";
|
||||
static final String STARTING_ASSEMBLY_OF_SOURCESET = "Starting assembly of the source set";
|
||||
static final String ENDING_ASSEMBLY_OF_SOURCESET = "Ending the assembly of the source set";
|
||||
static final String ADDED_DEFAULT_FILESET_WITH_BASE_DIRECTORY = "Addded a default FileSet with base directory: %s";
|
||||
static final String STARTING_EXECUTION_OF_ENHANCE_MOJO = "Starting execution of enhance mojo";
|
||||
static final String ENDING_EXECUTION_OF_ENHANCE_MOJO = "Ending execution of enhance mojo";
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.tooling.maven;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class EnhancementContextTest {
|
||||
|
||||
@Test
|
||||
void testGetClassLoader() {
|
||||
ClassLoader testLoader = new URLClassLoader(new URL[0]);
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertNull(context.getLoadingClassLoader());
|
||||
context = new EnhancementContext(testLoader, false, false, false, false);
|
||||
assertSame(testLoader, context.getLoadingClassLoader());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoBiDirectionalAssociationManagement() {
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertFalse(context.doBiDirectionalAssociationManagement(null));
|
||||
context = new EnhancementContext(null, true, false, false, false);
|
||||
assertTrue(context.doBiDirectionalAssociationManagement(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoDirtyCheckingInline() {
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertFalse(context.doDirtyCheckingInline(null));
|
||||
context = new EnhancementContext(null, false, true, false, false);
|
||||
assertTrue(context.doDirtyCheckingInline(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHasLazyLoadableAttributes() {
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertFalse(context.hasLazyLoadableAttributes(null));
|
||||
context = new EnhancementContext(null, false, false, true, false);
|
||||
assertTrue(context.hasLazyLoadableAttributes(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testIsLazyLoadable() {
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertFalse(context.isLazyLoadable(null));
|
||||
context = new EnhancementContext(null, false, false, true, false);
|
||||
assertTrue(context.isLazyLoadable(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDoExtendedEnhancement() {
|
||||
EnhancementContext context = new EnhancementContext(null, false, false, false, false);
|
||||
assertFalse(context.doExtendedEnhancement(null));
|
||||
context = new EnhancementContext(null, false, false, false, true);
|
||||
assertTrue(context.doExtendedEnhancement(null));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,644 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
* Copyright Red Hat Inc. and Hibernate Authors
|
||||
*/
|
||||
package org.hibernate.orm.tooling.maven;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.tools.JavaCompiler;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
import org.apache.maven.plugin.logging.Log;
|
||||
import org.apache.maven.shared.model.fileset.FileSet;
|
||||
import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl;
|
||||
import org.hibernate.bytecode.enhance.spi.EnhancementException;
|
||||
import org.hibernate.bytecode.enhance.spi.Enhancer;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
|
||||
public class HibernateEnhancerMojoTest {
|
||||
|
||||
@TempDir
|
||||
File tempDir;
|
||||
|
||||
private List<String> logMessages = new ArrayList<String>();
|
||||
|
||||
private Field classesDirectoryField;
|
||||
private Field fileSetsField;
|
||||
private Field sourceSetField;
|
||||
private Field enhancerField;
|
||||
|
||||
private File classesDirectory; // folder '${tempDir}/classes'
|
||||
private File fooFolder; // folder '${classesDirectory}/org/foo'
|
||||
private File barFolder; // folder '${classesDirectory}/bar'
|
||||
private File barClassFile; // file '${fooFolder}/Bar.class'
|
||||
private File fooTxtFile; // file '${barFolder}/Foo.txt'
|
||||
|
||||
private HibernateEnhancerMojo enhanceMojo;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
classesDirectoryField = HibernateEnhancerMojo.class.getDeclaredField("classesDirectory");
|
||||
classesDirectoryField.setAccessible(true);
|
||||
fileSetsField = HibernateEnhancerMojo.class.getDeclaredField("fileSets");
|
||||
fileSetsField.setAccessible(true);
|
||||
sourceSetField = HibernateEnhancerMojo.class.getDeclaredField("sourceSet");
|
||||
sourceSetField.setAccessible(true);
|
||||
enhancerField = HibernateEnhancerMojo.class.getDeclaredField("enhancer");
|
||||
enhancerField.setAccessible(true);
|
||||
enhanceMojo = new HibernateEnhancerMojo();
|
||||
enhanceMojo.setLog(createLog());
|
||||
classesDirectory = new File(tempDir, "classes");
|
||||
classesDirectory.mkdirs();
|
||||
classesDirectoryField.set(enhanceMojo, classesDirectory);
|
||||
fooFolder = new File(classesDirectory, "org/foo");
|
||||
fooFolder.mkdirs();
|
||||
barFolder = new File(classesDirectory, "bar");
|
||||
barFolder.mkdirs();
|
||||
barClassFile = new File(fooFolder, "Bar.class");
|
||||
barClassFile.createNewFile();
|
||||
fooTxtFile = new File (barFolder, "Foo.txt");
|
||||
fooTxtFile.createNewFile();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAssembleSourceSet() throws Exception {
|
||||
Method assembleSourceSetMethod = HibernateEnhancerMojo.class.getDeclaredMethod("assembleSourceSet");
|
||||
assembleSourceSetMethod.setAccessible(true);
|
||||
FileSet[] fileSets = new FileSet[1];
|
||||
fileSets[0] = new FileSet();
|
||||
fileSets[0].setDirectory(classesDirectory.getAbsolutePath());
|
||||
fileSetsField.set(enhanceMojo, fileSets);
|
||||
List<?> sourceSet = (List<?>)sourceSetField.get(enhanceMojo);
|
||||
assertTrue(sourceSet.isEmpty());
|
||||
assembleSourceSetMethod.invoke(enhanceMojo);
|
||||
assertFalse(sourceSet.isEmpty());
|
||||
assertTrue(sourceSet.contains(barClassFile));
|
||||
assertFalse(sourceSet.contains(fooTxtFile));
|
||||
assertEquals(1, sourceSet.size());
|
||||
// verify the log messages
|
||||
assertEquals(7, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_ASSEMBLY_OF_SOURCESET));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.PROCESSING_FILE_SET));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.USING_BASE_DIRECTORY.formatted(classesDirectory)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.ADDED_FILE_TO_SOURCE_SET.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.SKIPPING_NON_CLASS_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.FILESET_PROCESSED_SUCCESFULLY));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ENDING_ASSEMBLY_OF_SOURCESET));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAddFileSetToSourceSet() throws Exception {
|
||||
Method addFileSetToSourceSetMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"addFileSetToSourceSet",
|
||||
new Class[] { FileSet.class});
|
||||
addFileSetToSourceSetMethod.setAccessible(true);
|
||||
File fooClassFile = new File(fooFolder, "Foo.class");
|
||||
fooClassFile.createNewFile();
|
||||
File bazFolder = new File(classesDirectory, "org/baz");
|
||||
bazFolder.mkdirs();
|
||||
File bazClassFile = new File(bazFolder, "Baz.class");
|
||||
bazClassFile.createNewFile();
|
||||
FileSet fileSet = new FileSet();
|
||||
fileSet.setDirectory(classesDirectory.getAbsolutePath());
|
||||
fileSet.addInclude("**/Foo*");
|
||||
fileSet.addInclude("**/*.class");
|
||||
fileSet.addExclude("**/baz/**");
|
||||
addFileSetToSourceSetMethod.invoke(enhanceMojo, fileSet);
|
||||
// verify log messages
|
||||
assertEquals(6, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.PROCESSING_FILE_SET));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.USING_BASE_DIRECTORY.formatted(classesDirectory)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.ADDED_FILE_TO_SOURCE_SET.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.ADDED_FILE_TO_SOURCE_SET.formatted(fooClassFile)));
|
||||
assertFalse(logMessages.contains(INFO + HibernateEnhancerMojo.ADDED_FILE_TO_SOURCE_SET.formatted(bazClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.SKIPPING_NON_CLASS_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.FILESET_PROCESSED_SUCCESFULLY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateClassLoader() throws Exception {
|
||||
Method createClassLoaderMethod = HibernateEnhancerMojo.class.getDeclaredMethod("createClassLoader");
|
||||
createClassLoaderMethod.setAccessible(true);
|
||||
ClassLoader classLoader = (ClassLoader)createClassLoaderMethod.invoke(enhanceMojo);
|
||||
assertNotNull(classLoader);
|
||||
URL fooResource = classLoader.getResource("bar/Foo.txt");
|
||||
assertNotNull(fooResource);
|
||||
assertEquals(fooTxtFile.toURI().toURL(), fooResource);
|
||||
// verify log messages
|
||||
// verify log messages
|
||||
assertEquals(1, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateEnhancementContext() throws Exception {
|
||||
Method createEnhancementContextMethod = HibernateEnhancerMojo.class.getDeclaredMethod("createEnhancementContext");
|
||||
createEnhancementContextMethod.setAccessible(true);
|
||||
EnhancementContext enhancementContext = (EnhancementContext)createEnhancementContextMethod.invoke(enhanceMojo);
|
||||
URLClassLoader classLoader = (URLClassLoader)enhancementContext.getLoadingClassLoader();
|
||||
assertEquals(classesDirectory.toURI().toURL(), classLoader.getURLs()[0]);
|
||||
assertFalse(enhancementContext.doBiDirectionalAssociationManagement(null));
|
||||
assertFalse(enhancementContext.doDirtyCheckingInline(null));
|
||||
assertFalse(enhancementContext.hasLazyLoadableAttributes(null));
|
||||
assertFalse(enhancementContext.isLazyLoadable(null));
|
||||
assertFalse(enhancementContext.doExtendedEnhancement(null));
|
||||
// verify log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
logMessages.clear();
|
||||
Field enableAssociationManagementField = HibernateEnhancerMojo.class.getDeclaredField("enableAssociationManagement");
|
||||
enableAssociationManagementField.setAccessible(true);
|
||||
enableAssociationManagementField.set(enhanceMojo, Boolean.TRUE);
|
||||
enhancementContext = (EnhancementContext)createEnhancementContextMethod.invoke(enhanceMojo);
|
||||
assertEquals(classesDirectory.toURI().toURL(), classLoader.getURLs()[0]);
|
||||
assertTrue(enhancementContext.doBiDirectionalAssociationManagement(null));
|
||||
assertFalse(enhancementContext.doDirtyCheckingInline(null));
|
||||
assertFalse(enhancementContext.hasLazyLoadableAttributes(null));
|
||||
assertFalse(enhancementContext.isLazyLoadable(null));
|
||||
assertFalse(enhancementContext.doExtendedEnhancement(null));
|
||||
// verify log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
logMessages.clear();
|
||||
Field enableDirtyTrackingField = HibernateEnhancerMojo.class.getDeclaredField("enableDirtyTracking");
|
||||
enableDirtyTrackingField.setAccessible(true);
|
||||
enableDirtyTrackingField.set(enhanceMojo, Boolean.TRUE);
|
||||
enhancementContext = (EnhancementContext)createEnhancementContextMethod.invoke(enhanceMojo);
|
||||
assertEquals(classesDirectory.toURI().toURL(), classLoader.getURLs()[0]);
|
||||
assertTrue(enhancementContext.doBiDirectionalAssociationManagement(null));
|
||||
assertTrue(enhancementContext.doDirtyCheckingInline(null));
|
||||
assertFalse(enhancementContext.hasLazyLoadableAttributes(null));
|
||||
assertFalse(enhancementContext.isLazyLoadable(null));
|
||||
assertFalse(enhancementContext.doExtendedEnhancement(null));
|
||||
// verify log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
logMessages.clear();
|
||||
Field enableLazyInitializationField = HibernateEnhancerMojo.class.getDeclaredField("enableLazyInitialization");
|
||||
enableLazyInitializationField.setAccessible(true);
|
||||
enableLazyInitializationField.set(enhanceMojo, Boolean.TRUE);
|
||||
enhancementContext = (EnhancementContext)createEnhancementContextMethod.invoke(enhanceMojo);
|
||||
assertEquals(classesDirectory.toURI().toURL(), classLoader.getURLs()[0]);
|
||||
assertTrue(enhancementContext.doBiDirectionalAssociationManagement(null));
|
||||
assertTrue(enhancementContext.doDirtyCheckingInline(null));
|
||||
assertTrue(enhancementContext.hasLazyLoadableAttributes(null));
|
||||
assertTrue(enhancementContext.isLazyLoadable(null));
|
||||
assertFalse(enhancementContext.doExtendedEnhancement(null));
|
||||
// verify log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
logMessages.clear();
|
||||
Field enableExtendedEnhancementField = HibernateEnhancerMojo.class.getDeclaredField("enableExtendedEnhancement");
|
||||
enableExtendedEnhancementField.setAccessible(true);
|
||||
enableExtendedEnhancementField.set(enhanceMojo, Boolean.TRUE);
|
||||
enhancementContext = (EnhancementContext)createEnhancementContextMethod.invoke(enhanceMojo);
|
||||
assertEquals(classesDirectory.toURI().toURL(), classLoader.getURLs()[0]);
|
||||
assertTrue(enhancementContext.doBiDirectionalAssociationManagement(null));
|
||||
assertTrue(enhancementContext.doDirtyCheckingInline(null));
|
||||
assertTrue(enhancementContext.hasLazyLoadableAttributes(null));
|
||||
assertTrue(enhancementContext.isLazyLoadable(null));
|
||||
assertTrue(enhancementContext.doExtendedEnhancement(null));
|
||||
// verify log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
logMessages.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCreateEnhancer() throws Exception {
|
||||
Method createEnhancerMethod = HibernateEnhancerMojo.class.getDeclaredMethod("createEnhancer");
|
||||
createEnhancerMethod.setAccessible(true);
|
||||
Enhancer enhancer = (Enhancer)enhancerField.get(enhanceMojo);
|
||||
assertNull(enhancer);
|
||||
createEnhancerMethod.invoke(enhanceMojo);
|
||||
enhancer = (Enhancer)enhancerField.get(enhanceMojo);
|
||||
assertNotNull(enhancer);
|
||||
Field byteByddyEnhancementContextField = EnhancerImpl.class.getDeclaredField("enhancementContext");
|
||||
byteByddyEnhancementContextField.setAccessible(true);
|
||||
Object byteByddyEnhancementContext = byteByddyEnhancementContextField.get(enhancer);
|
||||
assertNotNull(byteByddyEnhancementContext);
|
||||
Field enhancementContextField = byteByddyEnhancementContext.getClass().getDeclaredField("enhancementContext");
|
||||
enhancementContextField.setAccessible(true);
|
||||
EnhancementContext enhancementContext = (EnhancementContext)enhancementContextField.get(byteByddyEnhancementContext);
|
||||
assertNotNull(enhancementContext);
|
||||
ClassLoader classLoader = enhancementContext.getLoadingClassLoader();
|
||||
assertNotNull(classLoader);
|
||||
assertNotNull(classLoader);
|
||||
URL fooResource = classLoader.getResource("bar/Foo.txt");
|
||||
assertNotNull(fooResource);
|
||||
assertEquals(fooTxtFile.toURI().toURL(), fooResource);
|
||||
// verify log messages
|
||||
assertEquals(3, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_BYTECODE_ENHANCER));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_ENHANCEMENT_CONTEXT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_URL_CLASSLOADER_FOR_FOLDER.formatted(classesDirectory)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDetermineClassName() throws Exception {
|
||||
Method determineClassNameMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"determineClassName",
|
||||
new Class[] { File.class });
|
||||
determineClassNameMethod.setAccessible(true);
|
||||
assertEquals("org.foo.Bar", determineClassNameMethod.invoke(enhanceMojo, barClassFile));
|
||||
// check log messages
|
||||
assertEquals(1, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverTypesForClass() throws Exception {
|
||||
final List<Boolean> hasRun = new ArrayList<Boolean>();
|
||||
Method discoverTypesForClassMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"discoverTypesForClass",
|
||||
new Class[] { File.class });
|
||||
discoverTypesForClassMethod.setAccessible(true);
|
||||
Enhancer enhancer = (Enhancer)Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class[] { Enhancer.class },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("discoverTypes")) {
|
||||
assertEquals("org.foo.Bar", args[0]);
|
||||
hasRun.add(0, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
enhancerField.set(enhanceMojo, enhancer);
|
||||
assertFalse(hasRun.contains(true));
|
||||
discoverTypesForClassMethod.invoke(enhanceMojo, barClassFile);
|
||||
assertTrue(hasRun.contains(true));
|
||||
// verify log messages
|
||||
assertEquals(3, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_DISCOVER_TYPES_FOR_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_DISCOVERED_TYPES_FOR_CLASS_FILE.formatted(barClassFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDiscoverTypes() throws Exception {
|
||||
final List<Boolean> hasRun = new ArrayList<Boolean>();
|
||||
Method discoverTypesMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"discoverTypes",
|
||||
new Class[] { });
|
||||
discoverTypesMethod.setAccessible(true);
|
||||
Enhancer enhancer = (Enhancer)Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class[] { Enhancer.class },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("discoverTypes")) {
|
||||
assertEquals("org.foo.Bar", args[0]);
|
||||
hasRun.add(0, true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
enhancerField.set(enhanceMojo, enhancer);
|
||||
assertFalse(hasRun.contains(true));
|
||||
discoverTypesMethod.invoke(enhanceMojo);
|
||||
assertFalse(hasRun.contains(true));
|
||||
// verify the log messages
|
||||
assertEquals(2, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_TYPE_DISCOVERY));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ENDING_TYPE_DISCOVERY));
|
||||
logMessages.clear();
|
||||
List<File> sourceSet = new ArrayList<File>();
|
||||
sourceSet.add(barClassFile);
|
||||
sourceSetField.set(enhanceMojo, sourceSet);
|
||||
discoverTypesMethod.invoke(enhanceMojo);
|
||||
assertTrue(hasRun.contains(true));
|
||||
// verify the log messages
|
||||
assertEquals(5, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_TYPE_DISCOVERY));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_DISCOVER_TYPES_FOR_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_DISCOVERED_TYPES_FOR_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ENDING_TYPE_DISCOVERY));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testClearFile() throws Exception {
|
||||
Method clearFileMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"clearFile",
|
||||
new Class[] { File.class });
|
||||
clearFileMethod.setAccessible(true);
|
||||
Files.writeString(fooTxtFile.toPath(), "foobar");
|
||||
fooTxtFile.setLastModified(0);
|
||||
assertEquals("foobar", new String(Files.readAllBytes(fooTxtFile.toPath())));
|
||||
boolean result = (boolean)clearFileMethod.invoke(enhanceMojo, new File("foobar"));
|
||||
assertFalse(result);
|
||||
result = (boolean)clearFileMethod.invoke(enhanceMojo, fooTxtFile);
|
||||
long modified = fooTxtFile.lastModified();
|
||||
assertTrue(result);
|
||||
// File should be empty
|
||||
assertTrue(Files.readAllBytes(fooTxtFile.toPath()).length == 0);
|
||||
// last modification 'after' should be after 'before'
|
||||
assertNotEquals(0, modified);
|
||||
assertTrue(modified > 0);
|
||||
// check log messages
|
||||
assertEquals(4, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_CLEAR_FILE.formatted("foobar")));
|
||||
assertTrue(logMessages.contains(ERROR + HibernateEnhancerMojo.UNABLE_TO_DELETE_FILE.formatted("foobar")));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_CLEAR_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_CLEARED_FILE.formatted(fooTxtFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWriteByteCodeToFile() throws Exception {
|
||||
Method writeByteCodeToFileMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"writeByteCodeToFile",
|
||||
new Class[] { byte[].class, File.class});
|
||||
writeByteCodeToFileMethod.setAccessible(true);
|
||||
fooTxtFile.setLastModified(0);
|
||||
// File fooTxtFile is empty
|
||||
assertTrue(Files.readAllBytes(fooTxtFile.toPath()).length == 0);
|
||||
writeByteCodeToFileMethod.invoke(enhanceMojo, "foobar".getBytes(), fooTxtFile);
|
||||
long modified = fooTxtFile.lastModified();
|
||||
// last modification 'after' should be after 'before'
|
||||
assertNotEquals(0, modified);
|
||||
assertTrue(modified > 0);
|
||||
// File should be contain 'foobar'
|
||||
assertEquals(new String(Files.readAllBytes(fooTxtFile.toPath())), "foobar");
|
||||
// check log messages
|
||||
assertEquals(4, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.WRITING_BYTE_CODE_TO_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_CLEAR_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_CLEARED_FILE.formatted(fooTxtFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.AMOUNT_BYTES_WRITTEN_TO_FILE.formatted(6, fooTxtFile)));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testEnhanceClass() throws Exception {
|
||||
final List<Integer> calls = new ArrayList<Integer>();
|
||||
calls.add(0, 0);
|
||||
Method enhanceClassMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"enhanceClass",
|
||||
new Class[] { File.class });
|
||||
enhanceClassMethod.setAccessible(true);
|
||||
Enhancer enhancer = (Enhancer)Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class[] { Enhancer.class },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
calls.set(0, calls.get(0) + 1);
|
||||
if (method.getName().equals("enhance")) {
|
||||
assertEquals("org.foo.Bar", args[0]);
|
||||
}
|
||||
if (calls.get(0) == 1) {
|
||||
return "foobar".getBytes();
|
||||
} else if (calls.get(0) == 2) {
|
||||
return null;
|
||||
} else {
|
||||
throw new EnhancementException("foobar");
|
||||
}
|
||||
}
|
||||
});
|
||||
long beforeRuns = barClassFile.lastModified();
|
||||
// First Run -> file is modified
|
||||
enhancerField.set(enhanceMojo, enhancer);
|
||||
assertEquals(0, calls.get(0));
|
||||
enhanceClassMethod.invoke(enhanceMojo, barClassFile);
|
||||
long afterFirstRun = barClassFile.lastModified();
|
||||
assertEquals(1, calls.get(0));
|
||||
assertTrue(afterFirstRun >= beforeRuns);
|
||||
assertEquals("foobar", new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
// verify log messages
|
||||
assertEquals(7, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_ENHANCE_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.WRITING_BYTE_CODE_TO_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_CLEAR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_CLEARED_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.AMOUNT_BYTES_WRITTEN_TO_FILE.formatted("foobar".length(), barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_ENHANCED_CLASS_FILE.formatted(barClassFile)));
|
||||
// Second Run -> file is not modified
|
||||
logMessages.clear();
|
||||
enhanceClassMethod.invoke(enhanceMojo, barClassFile);
|
||||
long afterSecondRun = barClassFile.lastModified();
|
||||
assertEquals(2, calls.get(0));
|
||||
assertEquals(afterSecondRun, afterFirstRun);
|
||||
assertEquals("foobar", new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
// verify log messages
|
||||
assertEquals(3, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_ENHANCE_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SKIPPING_FILE.formatted(barClassFile)));
|
||||
// Third Run -> exception!
|
||||
logMessages.clear();
|
||||
try {
|
||||
enhanceClassMethod.invoke(enhanceMojo, barClassFile);
|
||||
fail();
|
||||
} catch (Throwable e) {
|
||||
long afterThirdRun = barClassFile.lastModified();
|
||||
assertEquals(3, calls.get(0));
|
||||
assertEquals(afterThirdRun, afterFirstRun);
|
||||
assertEquals("foobar", new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
// verify log messages
|
||||
assertEquals(3, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_ENHANCE_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(ERROR + HibernateEnhancerMojo.ERROR_WHILE_ENHANCING_CLASS_FILE.formatted(barClassFile)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPerformEnhancement() throws Exception {
|
||||
final List<Boolean> hasRun = new ArrayList<Boolean>();
|
||||
Method performEnhancementMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"performEnhancement",
|
||||
new Class[] { });
|
||||
performEnhancementMethod.setAccessible(true);
|
||||
Enhancer enhancer = (Enhancer)Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class[] { Enhancer.class },
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("enhance")) {
|
||||
assertEquals("org.foo.Bar", args[0]);
|
||||
hasRun.add(0, true);
|
||||
}
|
||||
return "foobar".getBytes();
|
||||
}
|
||||
});
|
||||
enhancerField.set(enhanceMojo, enhancer);
|
||||
List<File> sourceSet = new ArrayList<File>();
|
||||
sourceSet.add(barClassFile);
|
||||
sourceSetField.set(enhanceMojo, sourceSet);
|
||||
long lastModified = barClassFile.lastModified();
|
||||
assertFalse(hasRun.contains(true));
|
||||
assertNotEquals("foobar", new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
performEnhancementMethod.invoke(enhanceMojo);
|
||||
assertTrue(hasRun.contains(true));
|
||||
assertEquals("foobar", new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
assertEquals(lastModified, barClassFile.lastModified());
|
||||
// verify the log messages
|
||||
assertEquals(9, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_CLASS_ENHANCEMENT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_ENHANCE_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.DETERMINE_CLASS_NAME_FOR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.WRITING_BYTE_CODE_TO_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.TRYING_TO_CLEAR_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_CLEARED_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.AMOUNT_BYTES_WRITTEN_TO_FILE.formatted("foobar".length(), barClassFile)));
|
||||
assertTrue(logMessages.contains(INFO + HibernateEnhancerMojo.SUCCESFULLY_ENHANCED_CLASS_FILE.formatted(barClassFile)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ENDING_CLASS_ENHANCEMENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testExecute() throws Exception {
|
||||
Method executeMethod = HibernateEnhancerMojo.class.getDeclaredMethod("execute", new Class[] {});
|
||||
executeMethod.setAccessible(true);
|
||||
final String barSource =
|
||||
"package org.foo;" +
|
||||
"import jakarta.persistence.Entity;" +
|
||||
"@Entity public class Bar { "+
|
||||
" private String foo; " +
|
||||
" String getFoo() { return foo; } " +
|
||||
" public void setFoo(String f) { foo = f; } " +
|
||||
"}";
|
||||
File barJavaFile = new File(fooFolder, "Bar.java");
|
||||
Files.writeString(barJavaFile.toPath(), barSource);
|
||||
final String fooSource =
|
||||
"package org.foo;" +
|
||||
"public class Foo { "+
|
||||
" private Bar bar; " +
|
||||
" Bar getBar() { return bar; } " +
|
||||
" public void setBar(Bar b) { bar = b; } " +
|
||||
"}";
|
||||
File fooJavaFile = new File(fooFolder, "Foo.java");
|
||||
Files.writeString(fooJavaFile.toPath(), fooSource);
|
||||
File fooClassFile = new File(fooFolder, "Foo.class");
|
||||
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
URL url = Entity.class.getProtectionDomain().getCodeSource().getLocation();
|
||||
String classpath = new File(url.toURI()).getAbsolutePath();
|
||||
String[] options = List.of(
|
||||
"-cp",
|
||||
classpath,
|
||||
barJavaFile.getAbsolutePath(),
|
||||
fooJavaFile.getAbsolutePath()).toArray(new String[] {});
|
||||
compiler.run(null, null, null, options);
|
||||
String barBytesString = new String(Files.readAllBytes(barClassFile.toPath()));
|
||||
String fooBytesString = new String(Files.readAllBytes(fooClassFile.toPath()));
|
||||
List<File> sourceSet = new ArrayList<File>();
|
||||
sourceSet.add(barClassFile);
|
||||
sourceSet.add(fooClassFile);
|
||||
sourceSetField.set(enhanceMojo, sourceSet);
|
||||
assertTrue(logMessages.isEmpty());
|
||||
executeMethod.invoke(enhanceMojo);
|
||||
assertNotEquals(barBytesString, new String(Files.readAllBytes(barClassFile.toPath())));
|
||||
assertEquals(fooBytesString, new String(Files.readAllBytes(fooClassFile.toPath())));
|
||||
URLClassLoader classLoader = new URLClassLoader(
|
||||
new URL[] {classesDirectory.toURI().toURL()},
|
||||
getClass().getClassLoader());
|
||||
Class<?> barClass = classLoader.loadClass("org.foo.Bar");
|
||||
assertNotNull(barClass);
|
||||
Method m = barClass.getMethod("$$_hibernate_getEntityInstance", new Class[]{});
|
||||
assertNotNull(m);
|
||||
Class<?> fooClass = classLoader.loadClass("org.foo.Foo");
|
||||
try {
|
||||
m = fooClass.getMethod("$$_hibernate_getEntityInstance", new Class[]{});
|
||||
fail();
|
||||
} catch (NoSuchMethodException e) {
|
||||
assertEquals("org.foo.Foo.$$_hibernate_getEntityInstance()", e.getMessage());
|
||||
}
|
||||
classLoader.close();
|
||||
// verify in the log messages at least if all the needed methods have been invoked
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_EXECUTION_OF_ENHANCE_MOJO));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ADDED_DEFAULT_FILESET_WITH_BASE_DIRECTORY.formatted(classesDirectory)));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_ASSEMBLY_OF_SOURCESET));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.CREATE_BYTECODE_ENHANCER));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_TYPE_DISCOVERY));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.STARTING_CLASS_ENHANCEMENT));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ENDING_EXECUTION_OF_ENHANCE_MOJO));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testProcessParameters() throws Exception {
|
||||
Method processParametersMethod = HibernateEnhancerMojo.class.getDeclaredMethod(
|
||||
"processParameters",
|
||||
new Class[] {});
|
||||
processParametersMethod.setAccessible(true);
|
||||
Field enableLazyInitializationField = HibernateEnhancerMojo.class.getDeclaredField("enableLazyInitialization");
|
||||
enableLazyInitializationField.setAccessible(true);
|
||||
Field enableDirtyTrackingField = HibernateEnhancerMojo.class.getDeclaredField("enableDirtyTracking");
|
||||
enableDirtyTrackingField.setAccessible(true);
|
||||
assertTrue(logMessages.isEmpty());
|
||||
assertNull(fileSetsField.get(enhanceMojo));
|
||||
processParametersMethod.invoke(enhanceMojo);
|
||||
assertEquals(3, logMessages.size());
|
||||
assertTrue(logMessages.contains(WARNING + HibernateEnhancerMojo.ENABLE_LAZY_INITIALIZATION_DEPRECATED));
|
||||
assertTrue(logMessages.contains(WARNING + HibernateEnhancerMojo.ENABLE_DIRTY_TRACKING_DEPRECATED));
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ADDED_DEFAULT_FILESET_WITH_BASE_DIRECTORY.formatted(classesDirectory)));
|
||||
FileSet[] fileSets = (FileSet[])fileSetsField.get(enhanceMojo);
|
||||
assertNotNull(fileSets);
|
||||
assertEquals(1, fileSets.length);
|
||||
assertEquals(classesDirectory.getAbsolutePath(), fileSets[0].getDirectory());
|
||||
fileSetsField.set(enhanceMojo, null);
|
||||
logMessages.clear();
|
||||
enableLazyInitializationField.set(enhanceMojo, Boolean.TRUE);
|
||||
enableDirtyTrackingField.set(enhanceMojo, Boolean.TRUE);
|
||||
processParametersMethod.invoke(enhanceMojo);
|
||||
assertEquals(1, logMessages.size());
|
||||
assertTrue(logMessages.contains(DEBUG + HibernateEnhancerMojo.ADDED_DEFAULT_FILESET_WITH_BASE_DIRECTORY.formatted(classesDirectory)));
|
||||
}
|
||||
|
||||
private Log createLog() {
|
||||
return (Log)Proxy.newProxyInstance(
|
||||
getClass().getClassLoader(),
|
||||
new Class[] { Log.class},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if ("info".equals(method.getName())) {
|
||||
logMessages.add(INFO + args[0]);
|
||||
} else if ("warn".equals(method.getName())) {
|
||||
logMessages.add(WARNING + args[0]);
|
||||
} else if ("error".equals(method.getName())) {
|
||||
logMessages.add(ERROR + args[0]);
|
||||
} else if ("debug".equals(method.getName())) {
|
||||
logMessages.add(DEBUG + args[0]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static final String DEBUG = "[DEBUG] ";
|
||||
static final String ERROR = "[ERROR] ";
|
||||
static final String WARNING = "[WARNING] ";
|
||||
static final String INFO = "[INFO] ";
|
||||
|
||||
}
|
Loading…
Reference in New Issue