Skip to content

Commit 3d9d05a

Browse files
committed
HHH-19879: Move Hibernate Tools' reveng module to Hibernate ORM and merge the relevant ant/gradle/maven plugins
- Add exporter to generate mapping.xml files Signed-off-by: Koen Aers <[email protected]>
1 parent fa581f9 commit 3d9d05a

File tree

9 files changed

+702
-125
lines changed

9 files changed

+702
-125
lines changed

tooling/hibernate-maven-plugin/src/intTest/java/org/hibernate/tool/maven/ExamplesTestIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class ExamplesTestIT {
2323

2424
public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
2525
private static File baseFolder;
26-
// private static File localRepo;
26+
// private static Figle localRepo;
2727

2828
private File projectFolder;
2929
private MavenCli mavenCli;
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.tool.maven;
6+
7+
import org.apache.maven.cli.MavenCli;
8+
import org.hibernate.tool.reveng.api.version.Version;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.io.TempDir;
11+
12+
import java.io.File;
13+
import java.net.URL;
14+
import java.nio.file.Files;
15+
import java.nio.file.Path;
16+
import java.nio.file.Paths;
17+
import java.util.Objects;
18+
19+
import static org.junit.jupiter.api.Assertions.assertFalse;
20+
import static org.junit.jupiter.api.Assertions.assertNotNull;
21+
import static org.junit.jupiter.api.Assertions.assertTrue;
22+
23+
public class TransformHbmTestIT {
24+
25+
public static final String MVN_HOME = "maven.multiModuleProjectDirectory";
26+
27+
@TempDir
28+
private Path projectPath;
29+
30+
@Test
31+
public void testSimpleHbmTransformation() throws Exception {
32+
System.setProperty(MVN_HOME, projectPath.toAbsolutePath().toString());
33+
writePomFile();
34+
copyHbmFile();
35+
runTransformHbmToOrm();
36+
}
37+
38+
private void writePomFile() throws Exception {
39+
File pomFile = new File(projectPath.toFile(), "pom.xml");
40+
assertFalse(pomFile.exists());
41+
Path pomPath = projectPath.resolve("pom.xml");
42+
Files.writeString(pomPath, simplePomContents);
43+
assertTrue(pomFile.exists());
44+
}
45+
46+
private void copyHbmFile() throws Exception {
47+
URL originUrl = getClass().getResource("simple.hbm.xml");
48+
assertNotNull(originUrl);
49+
Path originPath = Paths.get(Objects.requireNonNull(originUrl).toURI());
50+
File destinationDir = new File(projectPath.toFile(), "src/main/resources/");
51+
assertTrue(destinationDir.mkdirs());
52+
File destinationFile = new File(destinationDir, "simple.hbm.xml");
53+
assertFalse(destinationFile.exists());
54+
Files.copy(originPath, destinationFile.toPath());
55+
assertTrue(destinationFile.exists());
56+
}
57+
58+
private void runTransformHbmToOrm() throws Exception {
59+
File destinationDir = new File(projectPath.toFile(), "src/main/resources/");
60+
File ormXmlFile = new File(destinationDir, "simple.mapping.xml");
61+
assertFalse(ormXmlFile.exists());
62+
new MavenCli().doMain(
63+
new String[] {
64+
"compile",
65+
"org.hibernate.orm:hibernate-maven-plugin:" + Version.versionString() + ":hbm2orm"
66+
},
67+
projectPath.toAbsolutePath().toString(),
68+
null,
69+
null);
70+
// Check the existence of the transformed file
71+
assertTrue(ormXmlFile.exists());
72+
// Check if it's pretty printed
73+
assertTrue(Files.readString(ormXmlFile.toPath()).contains("\n <table name=\"Foo\"/>\n"));
74+
}
75+
76+
private static File determineBaseFolder() throws Exception {
77+
Class<?> thisClass = TransformHbmTestIT.class;
78+
URL classUrl = thisClass.getResource("/" + thisClass.getName().replace(".", "/") + ".class");
79+
assert classUrl != null;
80+
File result = new File(classUrl.toURI());
81+
for (int i = 0; i < thisClass.getName().chars().filter(ch -> ch == '.').count() + 1; i++) {
82+
result = result.getParentFile();
83+
}
84+
return result;
85+
}
86+
87+
private static final String simplePomContents =
88+
"""
89+
<project>
90+
<modelVersion>4.0.0</modelVersion>
91+
<groupId>org.hibernate.tool.maven.test</groupId>
92+
<artifactId>simplest</artifactId>
93+
<version>0.1-SNAPSHOT</version>
94+
</project>
95+
""";
96+
97+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2004 - 2025 Red Hat, Inc.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" basis,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<!DOCTYPE hibernate-mapping PUBLIC
18+
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
19+
"https://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
20+
<hibernate-mapping>
21+
22+
<class name="org.bar.Foo">
23+
<id name="id" type="long">
24+
<generator class="assigned"/>
25+
</id>
26+
<property name="name" type="string"/>
27+
</class>
28+
29+
</hibernate-mapping>

tooling/hibernate-maven-plugin/src/main/java/org/hibernate/tool/maven/TransformHbmMojo.java

Lines changed: 40 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -4,133 +4,54 @@
44
*/
55
package org.hibernate.tool.maven;
66

7-
import jakarta.xml.bind.JAXBException;
8-
import jakarta.xml.bind.Marshaller;
9-
import org.apache.maven.plugin.AbstractMojo;
10-
import org.apache.maven.plugins.annotations.Mojo;
11-
import org.apache.maven.plugins.annotations.Parameter;
12-
import org.apache.maven.plugins.annotations.ResolutionScope;
13-
import org.hibernate.boot.MetadataSources;
14-
import org.hibernate.boot.jaxb.Origin;
15-
import org.hibernate.boot.jaxb.SourceType;
16-
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
17-
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
18-
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
19-
import org.hibernate.boot.jaxb.internal.MappingBinder;
20-
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
21-
import org.hibernate.boot.jaxb.spi.Binding;
22-
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
23-
import org.hibernate.boot.spi.MetadataImplementor;
24-
import org.hibernate.cfg.JdbcSettings;
25-
import org.hibernate.dialect.H2Dialect;
26-
import org.hibernate.service.ServiceRegistry;
7+
import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_RESOURCES;
278

289
import java.io.File;
29-
import java.io.FileInputStream;
30-
import java.io.IOException;
31-
import java.io.Serial;
10+
import java.net.MalformedURLException;
11+
import java.net.URL;
12+
import java.net.URLClassLoader;
3213
import java.util.ArrayList;
3314
import java.util.List;
3415
import java.util.Objects;
3516

36-
import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_RESOURCES;
17+
import org.apache.maven.artifact.DependencyResolutionRequiredException;
18+
import org.apache.maven.plugin.AbstractMojo;
19+
import org.apache.maven.plugins.annotations.Mojo;
20+
import org.apache.maven.plugins.annotations.Parameter;
21+
import org.apache.maven.plugins.annotations.ResolutionScope;
22+
import org.apache.maven.project.MavenProject;
23+
24+
import org.hibernate.tool.reveng.internal.export.mapping.MappingExporter;
3725

3826
@Mojo(
39-
name = "hbm2orm",
40-
defaultPhase = GENERATE_RESOURCES,
41-
requiresDependencyResolution = ResolutionScope.RUNTIME)
27+
name = "hbm2orm",
28+
defaultPhase = GENERATE_RESOURCES,
29+
requiresDependencyResolution = ResolutionScope.RUNTIME)
4230
public class TransformHbmMojo extends AbstractMojo {
4331

4432
@Parameter(defaultValue = "${project.basedir}/src/main/resources")
4533
private File inputFolder;
4634

47-
@Override
48-
public void execute() {
49-
MappingBinder mappingBinder = new MappingBinder(
50-
MappingBinder.class.getClassLoader()::getResourceAsStream,
51-
UnsupportedFeatureHandling.ERROR);
52-
List<File> hbmFiles = getHbmFiles(inputFolder);
53-
List<Binding<JaxbHbmHibernateMapping>> hbmMappings = getHbmMappings(hbmFiles, mappingBinder);
54-
performTransformation(hbmMappings, mappingBinder, createServiceRegistry());
55-
}
56-
57-
private ServiceRegistry createServiceRegistry() {
58-
StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder();
59-
ssrb.clearSettings();
60-
ssrb.applySetting(JdbcSettings.ALLOW_METADATA_ON_BOOT, false);
61-
// Choose the H2 dialect by default, make this configurable
62-
ssrb.applySetting(JdbcSettings.DIALECT, H2Dialect.class.getName());
63-
return ssrb.build();
64-
}
35+
@Parameter(defaultValue = "true")
36+
private boolean format;
6537

66-
private void performTransformation(
67-
List<Binding<JaxbHbmHibernateMapping>> hbmBindings,
68-
MappingBinder mappingBinder,
69-
ServiceRegistry serviceRegistry) {
70-
Marshaller marshaller = createMarshaller(mappingBinder);
71-
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
72-
hbmBindings.forEach( metadataSources::addHbmXmlBinding );
73-
List<Binding<JaxbEntityMappingsImpl>> transformedBindings = HbmXmlTransformer.transform(
74-
hbmBindings,
75-
(MetadataImplementor) metadataSources.buildMetadata(),
76-
UnsupportedFeatureHandling.ERROR
77-
);
78-
for (int i = 0; i < hbmBindings.size(); i++) {
79-
Binding<JaxbHbmHibernateMapping> hbmBinding = hbmBindings.get( i );
80-
Binding<JaxbEntityMappingsImpl> transformedBinding = transformedBindings.get( i );
38+
@Parameter(defaultValue = "${project}", readonly = true, required = true)
39+
private MavenProject project;
8140

82-
HbmXmlOrigin origin = (HbmXmlOrigin)hbmBinding.getOrigin();
83-
File hbmXmlFile = origin.getHbmXmlFile();
84-
85-
marshall(marshaller, transformedBinding.getRoot(), hbmXmlFile);
86-
}
87-
}
88-
89-
private List<Binding<JaxbHbmHibernateMapping>> getHbmMappings(List<File> hbmXmlFiles, MappingBinder mappingBinder) {
90-
List<Binding<JaxbHbmHibernateMapping>> result = new ArrayList<>();
91-
hbmXmlFiles.forEach((hbmXmlFile) -> {
92-
final String fullPath = hbmXmlFile.getAbsolutePath();
93-
getLog().info("Adding file: '" + fullPath + "' to the list to be transformed.");
94-
Origin origin = new HbmXmlOrigin( hbmXmlFile );
95-
Binding<JaxbHbmHibernateMapping> binding = bindMapping( mappingBinder, hbmXmlFile, origin );
96-
result.add(binding);
97-
});
98-
return result;
99-
}
100-
101-
private void marshall(Marshaller marshaller, JaxbEntityMappingsImpl mappings, File hbmXmlFile) {
102-
File mappingXmlFile = new File(
103-
hbmXmlFile.getParentFile(),
104-
hbmXmlFile.getName().replace(".hbm.xml", ".mapping.xml"));
105-
getLog().info("Marshalling file: " + hbmXmlFile.getAbsolutePath() + " into " + mappingXmlFile.getAbsolutePath());
106-
try {
107-
marshaller.marshal( mappings, mappingXmlFile );
108-
}
109-
catch (JAXBException e) {
110-
throw new RuntimeException(
111-
"Unable to marshall mapping JAXB representation to file `" + mappingXmlFile.getAbsolutePath() + "`",
112-
e
113-
);
114-
}
115-
}
116-
117-
private Binding<JaxbHbmHibernateMapping> bindMapping(
118-
MappingBinder mappingBinder, File hbmXmlFile, Origin origin) {
119-
try ( final FileInputStream fileStream = new FileInputStream(hbmXmlFile) ) {
120-
return mappingBinder.bind( fileStream, origin );
121-
}
122-
catch (IOException e) {
123-
getLog().warn( "Unable to open hbm.xml file `" + hbmXmlFile.getAbsolutePath() + "` for transformation", e );
124-
return null;
125-
}
126-
}
127-
128-
private Marshaller createMarshaller(MappingBinder mappingBinder) {
41+
@Override
42+
public void execute() {
43+
ClassLoader original = Thread.currentThread().getContextClassLoader();
12944
try {
130-
return mappingBinder.mappingJaxbContext().createMarshaller();
45+
Thread.currentThread().setContextClassLoader(createClassLoader(original));
46+
getLog().info("Starting " + this.getClass().getSimpleName() + "...");
47+
MappingExporter mappingExporter = new MappingExporter();
48+
mappingExporter.setHbmFiles(getHbmFiles(inputFolder));
49+
mappingExporter.setFormatResult(format);
50+
mappingExporter.start();
51+
getLog().info("Finished " + this.getClass().getSimpleName() + "!");
13152
}
132-
catch (JAXBException e) {
133-
throw new RuntimeException("Unable to create JAXB Marshaller", e);
53+
finally {
54+
Thread.currentThread().setContextClassLoader(original);
13455
}
13556
}
13657

@@ -149,22 +70,17 @@ private List<File> getHbmFiles(File f) {
14970
return result;
15071
}
15172

152-
private static class HbmXmlOrigin extends Origin {
153-
154-
@Serial
155-
private static final long serialVersionUID = 1L;
156-
157-
private final File hbmXmlFile;
158-
159-
public HbmXmlOrigin(File hbmXmlFile) {
160-
super( SourceType.FILE, hbmXmlFile.getAbsolutePath() );
161-
this.hbmXmlFile = hbmXmlFile;
73+
private ClassLoader createClassLoader(ClassLoader parent) {
74+
ArrayList<URL> urls = new ArrayList<>();
75+
try {
76+
for (String cpe : project.getRuntimeClasspathElements()) {
77+
urls.add(new File(cpe).toURI().toURL());
78+
}
16279
}
163-
164-
public File getHbmXmlFile() {
165-
return hbmXmlFile;
80+
catch (DependencyResolutionRequiredException | MalformedURLException e) {
81+
throw new RuntimeException("Problem while constructing project classloader", e);
16682
}
167-
83+
return new URLClassLoader(urls.toArray(new URL[0]), parent);
16884
}
16985

17086
}

tooling/hibernate-reveng/hibernate-reveng.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ dependencies {
1111
implementation "com.google.googlejavaformat:google-java-format:1.27.0"
1212
implementation "org.freemarker:freemarker:2.3.34"
1313
implementation "org.antlr:antlr4-runtime:4.13.2"
14+
implementation "jakarta.xml.bind:jakarta.xml.bind-api:4.0.2"
1415
}

0 commit comments

Comments
 (0)