HHH-18060 - HbmXmlTransformer

testing an alternative approach using the boot model
This commit is contained in:
Steve Ebersole 2024-07-02 08:24:39 -05:00
parent 2d0f1a76cc
commit 6bd37f535c
7 changed files with 169 additions and 19 deletions

View File

@ -299,8 +299,9 @@ public class StandardServiceRegistryBuilder {
/** /**
* Discard all the settings applied so far. * Discard all the settings applied so far.
*/ */
public void clearSettings() { public StandardServiceRegistryBuilder clearSettings() {
settings.clear(); settings.clear();
return this;
} }
/** /**

View File

@ -21,6 +21,7 @@ import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.SourceTask; import org.gradle.api.tasks.SourceTask;
import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.TaskAction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer; import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
@ -28,7 +29,12 @@ import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.internal.MappingBinder;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.jaxb.spi.Binding;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.boot.xsd.MappingXsdSupport;
import org.hibernate.cfg.JdbcSettings;
import org.hibernate.dialect.Database;
import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller; import jakarta.xml.bind.Marshaller;
@ -57,7 +63,8 @@ import jakarta.xml.bind.Marshaller;
*/ */
@CacheableTask @CacheableTask
public abstract class TransformHbmXmlTask extends SourceTask { public abstract class TransformHbmXmlTask extends SourceTask {
private final Property<TransformationNaming> renaming; private final TransformationNaming renaming;
private final Property<String> targetDatabaseName;
private final Property<UnsupportedFeatureHandling> unsupportedFeatures; private final Property<UnsupportedFeatureHandling> unsupportedFeatures;
private final Property<Boolean> deleteHbmFiles; private final Property<Boolean> deleteHbmFiles;
@ -66,8 +73,10 @@ public abstract class TransformHbmXmlTask extends SourceTask {
public TransformHbmXmlTask() { public TransformHbmXmlTask() {
this.outputDirectory = getProject().getObjects().directoryProperty(); this.outputDirectory = getProject().getObjects().directoryProperty();
this.renaming = getProject().getObjects().property( TransformationNaming.class ); this.renaming = new TransformationNaming( getProject().getObjects() );
this.renaming.set( new TransformationNaming( getProject().getObjects() ) );
this.targetDatabaseName = getProject().getObjects().property( String.class );
this.targetDatabaseName.convention( "H2" );
this.unsupportedFeatures = getProject().getObjects().property( UnsupportedFeatureHandling.class ); this.unsupportedFeatures = getProject().getObjects().property( UnsupportedFeatureHandling.class );
this.unsupportedFeatures.convention( UnsupportedFeatureHandling.ERROR ); this.unsupportedFeatures.convention( UnsupportedFeatureHandling.ERROR );
@ -81,10 +90,19 @@ public abstract class TransformHbmXmlTask extends SourceTask {
*/ */
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Nested @Nested
public Property<TransformationNaming> getRenaming() { public TransformationNaming getRenaming() {
return renaming; return renaming;
} }
/**
* @see Database
*/
@SuppressWarnings("unused")
@Input
public Property<String> getTargetDatabaseName() {
return targetDatabaseName;
}
/** /**
* How should features supported in `hbm.xml` files, which are not supported for transformation, be handled? * How should features supported in `hbm.xml` files, which are not supported for transformation, be handled?
*/ */
@ -108,7 +126,7 @@ public abstract class TransformHbmXmlTask extends SourceTask {
* E.g. transforming the resource `org/hibernate/test/my_mappings.hbm.xml` * E.g. transforming the resource `org/hibernate/test/my_mappings.hbm.xml`
* into `/home/me/hibernate` would transform the HBM mapping and save it * into `/home/me/hibernate` would transform the HBM mapping and save it
* as `/home/me/hibernate/org/hibernate/test/my_mappings.hbm.xml` (depending * as `/home/me/hibernate/org/hibernate/test/my_mappings.hbm.xml` (depending
* on {@link #getRenaming() naming} any config * on {@link #getRenaming() naming} config)
*/ */
@OutputDirectory @OutputDirectory
public DirectoryProperty getOutputDirectory() { public DirectoryProperty getOutputDirectory() {
@ -122,14 +140,6 @@ public abstract class TransformHbmXmlTask extends SourceTask {
unsupportedFeatures.getOrElse( UnsupportedFeatureHandling.ERROR ) unsupportedFeatures.getOrElse( UnsupportedFeatureHandling.ERROR )
); );
final Marshaller marshaller;
try {
marshaller = mappingBinder.mappingJaxbContext().createMarshaller();
}
catch (JAXBException e) {
throw new RuntimeException( "Unable to create JAXB Marshaller", e );
}
final List<Binding<JaxbHbmHibernateMapping>> hbmBindings = new ArrayList<>(); final List<Binding<JaxbHbmHibernateMapping>> hbmBindings = new ArrayList<>();
getSource().forEach( (hbmXmlFile) -> { getSource().forEach( (hbmXmlFile) -> {
final Origin origin = new OriginImpl( hbmXmlFile ); final Origin origin = new OriginImpl( hbmXmlFile );
@ -137,8 +147,25 @@ public abstract class TransformHbmXmlTask extends SourceTask {
hbmBindings.add( hbmBinding ); hbmBindings.add( hbmBinding );
} ); } );
try ( StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.clearSettings()
.applySetting( JdbcSettings.JAKARTA_HBM2DDL_DB_NAME, targetDatabaseName.get() )
.applySetting( JdbcSettings.ALLOW_METADATA_ON_BOOT, false )
.build() ) {
performTransformation( hbmBindings, mappingBinder, serviceRegistry );
}
}
private void performTransformation(
List<Binding<JaxbHbmHibernateMapping>> hbmBindings,
MappingBinder mappingBinder, StandardServiceRegistry serviceRegistry) {
final MetadataSources metadataSources = new MetadataSources( serviceRegistry );
hbmBindings.forEach( metadataSources::addHbmXmlBinding );
final List<Binding<JaxbEntityMappingsImpl>> transformedBindings = HbmXmlTransformer.transform( final List<Binding<JaxbEntityMappingsImpl>> transformedBindings = HbmXmlTransformer.transform(
hbmBindings, hbmBindings,
(MetadataImplementor) metadataSources.buildMetadata(),
serviceRegistry,
unsupportedFeatures.get() unsupportedFeatures.get()
); );
@ -160,6 +187,16 @@ public abstract class TransformHbmXmlTask extends SourceTask {
final File copyFile = determineCopyFile( copyName, hbmXmlFile ); final File copyFile = determineCopyFile( copyName, hbmXmlFile );
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
copyFile.getParentFile().mkdirs(); copyFile.getParentFile().mkdirs();
final Marshaller marshaller;
try {
marshaller = mappingBinder.mappingJaxbContext().createMarshaller();
}
catch (JAXBException e) {
throw new RuntimeException( "Unable to create JAXB Marshaller", e );
}
try { try {
marshaller.marshal( transformedBinding.getRoot(), copyFile ); marshaller.marshal( transformedBinding.getRoot(), copyFile );
} }
@ -194,11 +231,6 @@ public abstract class TransformHbmXmlTask extends SourceTask {
private String determineCopyName(File hbmXmlFile) { private String determineCopyName(File hbmXmlFile) {
final String hbmXmlFileName = hbmXmlFile.getName(); final String hbmXmlFileName = hbmXmlFile.getName();
if ( !renaming.isPresent() ) {
return hbmXmlFileName;
}
final TransformationNaming renaming = this.renaming.get();
if ( renaming.areNoneDefined() ) { if ( renaming.areNoneDefined() ) {
return hbmXmlFileName; return hbmXmlFileName;
} }

View File

@ -12,6 +12,7 @@ import javax.inject.Inject;
import org.gradle.api.model.ObjectFactory; import org.gradle.api.model.ObjectFactory;
import org.gradle.api.provider.Property; import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
/** /**
* Defines how we rename a file being transformed. * Defines how we rename a file being transformed.
@ -43,6 +44,7 @@ public class TransformationNaming implements Serializable {
* @see #getExtension() * @see #getExtension()
*/ */
@Input @Input
@Optional
public Property<String> getPrefix() { public Property<String> getPrefix() {
return prefix; return prefix;
} }
@ -57,11 +59,13 @@ public class TransformationNaming implements Serializable {
* @see #getExtension() * @see #getExtension()
*/ */
@Input @Input
@Optional
public Property<String> getSuffix() { public Property<String> getSuffix() {
return suffix; return suffix;
} }
@Input @Input
@Optional
public Property<String> getExtension() { public Property<String> getExtension() {
return extension; return extension;
} }

View File

@ -0,0 +1,64 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
*/
package org.hibernate.orm.tooling.gradle;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.BuildTask;
import org.gradle.testkit.runner.GradleRunner;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import static org.assertj.core.api.Assertions.assertThat;
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;
/**
* Basic functional tests
*
* @author Steve Ebersole
*/
class HbmTransformerTests {
@Test
void testSimpleTransformation(@TempDir Path projectDir) throws IOException {
final String buildFilePath = "hbm/build.gradle";
Copier.copyProject( buildFilePath, projectDir );
System.out.println( "Starting execution ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" );
final GradleRunner gradleRunner = GradleRunner.create()
.withProjectDir( projectDir.toFile() )
.withPluginClasspath()
.withDebug( true )
.withArguments( "clean", "hbmTransform", "--stacktrace", "--no-build-cache" )
.forwardOutput();
final BuildResult result = gradleRunner.build();
final BuildTask transformationResult = result.task( ":hbmTransform" );
assertThat( transformationResult ).isNotNull();
assertThat( transformationResult.getOutcome() ).isEqualTo( SUCCESS );
final File targetDir = new File( projectDir.toFile(), "build" );
final File transformationOutputDir = new File( targetDir, "resources/hbm-transformed" );
assertThat( transformationOutputDir ).exists();
assertThat( transformationOutputDir ).isNotEmptyDirectory();
final File[] transformedFiles = transformationOutputDir.listFiles();
assertThat( transformedFiles ).hasSize( 1 );
final String transformedFileContent = Files.readString( transformedFiles[0].toPath() );
assertThat( transformedFileContent ).doesNotContain( "<hibernate-mapping" );
assertThat( transformedFileContent ).doesNotContain( "</hibernate-mapping>" );
assertThat( transformedFileContent ).contains( "<entity-mappings" );
assertThat( transformedFileContent ).contains( "<entity name=\"simple\" metadata-complete=\"true\">" );
assertThat( transformedFileContent ).contains( "</entity-mappings>" );
}
}

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
import org.hibernate.orm.tooling.gradle.misc.TransformHbmXmlTask
plugins {
id 'java'
id 'org.hibernate.orm'
}
repositories {
mavenCentral()
maven {
name 'jboss-snapshots-repository'
url 'https://repository.jboss.org/nexus/content/repositories/snapshots'
}
}
dependencies {
// NOTE : The version used here is irrelevant in terms of testing the plugin.
// We just need a resolvable version
implementation 'org.hibernate.orm:hibernate-core:6.1.0.Final'
}
tasks.register( "hbmTransform", TransformHbmXmlTask ) {
source "src/main/resources"
getRenaming().getExtension().set( "xml" )
getOutputDirectory().set( project.layout.buildDirectory.dir( "resources/hbm-transformed" ) )
}

View File

@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!--
~ Hibernate, Relational Persistence for Idiomatic Java
~
~ License: GNU Lesser General Public License (LGPL), version 2.1 or later.
~ See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
-->
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class entity-name="simple">
<id name="id" type="integer"/>
<property name="name" type="string"/>
</class>
</hibernate-mapping>