HHH-18644 - New and improved hibernate-maven-plugin

Signed-off-by: Koen Aers <koen.aers@gmail.com>
This commit is contained in:
Koen Aers 2024-10-28 13:24:49 +01:00 committed by Steve Ebersole
parent 817355f8a4
commit 707c3a788f
17 changed files with 1587 additions and 10 deletions

View File

@ -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 {

View File

@ -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();
}
}

View File

@ -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);
}
}
}

View File

@ -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" );
}
}

View File

@ -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]);
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1 @@
org.gradle.internal.logging.slf4j.OutputEventListenerBackedLoggerContext org.hibernate.build.maven.embedder.logging.Slf4jConfiguration

View File

@ -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')
})
}
}

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,15 @@
package org.foo;
public class Foo {
private Bar bar;
Bar getBar() {
return bar;
}
public void setBar(Bar b) {
bar = b;
}
}

View File

@ -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.");
}

View File

@ -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;
}
}

View File

@ -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";
}

View File

@ -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));
}
}

View File

@ -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] ";
}