Skip to content

Commit d722226

Browse files
committed
HBX-3242: Create an exporter type to generate mapping.xml files
- MappingExporter has full functionality (but still needs some refactoring) - MappingExporterTest has tests added but still needs a test for the 'start' method Signed-off-by: Koen Aers <koen.aers@gmail.com>
1 parent 582fe6c commit d722226

File tree

3 files changed

+339
-2
lines changed

3 files changed

+339
-2
lines changed

orm/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
<dependency>
4141
<groupId>com.google.googlejavaformat</groupId>
4242
<artifactId>google-java-format</artifactId>
43+
</dependency>
44+
<dependency>
45+
<groupId>jakarta.xml.bind</groupId>
46+
<artifactId>jakarta.xml.bind-api</artifactId>
4347
</dependency>
4448
<dependency>
4549
<groupId>org.antlr</groupId>
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,152 @@
11
package org.hibernate.tool.internal.export.mapping;
22

3+
import jakarta.xml.bind.JAXBException;
4+
import jakarta.xml.bind.Marshaller;
5+
import org.apache.commons.collections4.list.UnmodifiableList;
6+
import org.hibernate.boot.MetadataSources;
7+
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping;
8+
import org.hibernate.boot.jaxb.hbm.transform.HbmXmlTransformer;
9+
import org.hibernate.boot.jaxb.hbm.transform.UnsupportedFeatureHandling;
10+
import org.hibernate.boot.jaxb.internal.MappingBinder;
11+
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
12+
import org.hibernate.boot.jaxb.spi.Binding;
13+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
14+
import org.hibernate.boot.spi.MetadataImplementor;
15+
import org.hibernate.cfg.JdbcSettings;
16+
import org.hibernate.service.ServiceRegistry;
317
import org.hibernate.tool.api.export.Exporter;
18+
import org.hibernate.tool.api.xml.XMLPrettyPrinter;
19+
import org.hibernate.tool.internal.util.DummyDialect;
420

21+
import java.io.File;
22+
import java.io.FileInputStream;
23+
import java.io.IOException;
24+
import java.util.ArrayList;
25+
import java.util.List;
526
import java.util.Properties;
27+
import java.util.logging.Logger;
628

729
public class MappingExporter implements Exporter {
830

31+
private static final Logger LOGGER = Logger.getLogger( MappingExporter.class.getName() );
32+
33+
private UnmodifiableList<File> hbmXmlFiles;
34+
private boolean formatResult = true;
35+
36+
public void setHbmFiles(List<File> fileList) {
37+
hbmXmlFiles = new UnmodifiableList<>( fileList );
38+
}
39+
40+
public void setFormatResult(boolean formatResult) {
41+
this.formatResult = formatResult;
42+
}
43+
944
@Override
1045
public Properties getProperties() {
1146
return null;
1247
}
1348

1449
@Override
1550
public void start() {
51+
MappingBinder mappingBinder = createMappingBinder();
52+
List<Binding<JaxbHbmHibernateMapping>> hbmMappings = getHbmMappings(mappingBinder);
53+
performTransformation(hbmMappings, mappingBinder, createServiceRegistry(), formatResult);
1654
}
55+
56+
private ServiceRegistry createServiceRegistry() {
57+
StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder();
58+
ssrb.clearSettings();
59+
ssrb.applySetting(JdbcSettings.ALLOW_METADATA_ON_BOOT, false);
60+
ssrb.applySetting(JdbcSettings.DIALECT, DummyDialect.class.getName());
61+
return ssrb.build();
62+
}
63+
64+
private MappingBinder createMappingBinder() {
65+
return new MappingBinder(
66+
MappingBinder.class.getClassLoader()::getResourceAsStream,
67+
UnsupportedFeatureHandling.ERROR);
68+
}
69+
70+
private List<Binding<JaxbHbmHibernateMapping>> getHbmMappings(MappingBinder mappingBinder) {
71+
List<Binding<JaxbHbmHibernateMapping>> result = new ArrayList<>();
72+
hbmXmlFiles.forEach((hbmXmlFile) -> {
73+
final String fullPath = hbmXmlFile.getAbsolutePath();
74+
LOGGER.info("Adding file: '" + fullPath + "' to the list to be transformed.");
75+
HbmXmlOrigin origin = new HbmXmlOrigin( hbmXmlFile );
76+
Binding<JaxbHbmHibernateMapping> binding = bindMapping( mappingBinder, origin );
77+
result.add(binding);
78+
});
79+
return result;
80+
}
81+
82+
private Binding<JaxbHbmHibernateMapping> bindMapping(
83+
MappingBinder mappingBinder, HbmXmlOrigin origin) {
84+
File hbmXmlFile = origin.getHbmXmlFile();
85+
try ( final FileInputStream fileStream = new FileInputStream(hbmXmlFile) ) {
86+
return mappingBinder.bind( fileStream, origin );
87+
}
88+
catch (IOException e) {
89+
LOGGER.info( "Unable to open hbm.xml file `" + hbmXmlFile.getAbsolutePath() + "` for transformation");
90+
return null;
91+
}
92+
}
93+
94+
private Marshaller createMarshaller(MappingBinder mappingBinder) {
95+
try {
96+
return mappingBinder.mappingJaxbContext().createMarshaller();
97+
}
98+
catch (JAXBException e) {
99+
throw new RuntimeException("Unable to create JAXB Marshaller", e);
100+
}
101+
}
102+
103+
private void marshall(
104+
Marshaller marshaller,
105+
JaxbEntityMappingsImpl mappings,
106+
File hbmXmlFile,
107+
boolean formatResult) {
108+
File mappingXmlFile = new File(
109+
hbmXmlFile.getParentFile(),
110+
hbmXmlFile.getName().replace(".hbm.xml", ".mapping.xml"));
111+
LOGGER.info("Marshalling file: " + hbmXmlFile.getAbsolutePath() + " into " + mappingXmlFile.getAbsolutePath());
112+
try {
113+
marshaller.marshal( mappings, mappingXmlFile );
114+
if (formatResult) {
115+
XMLPrettyPrinter.prettyPrintFile(mappingXmlFile);
116+
}
117+
}
118+
catch (JAXBException e) {
119+
throw new RuntimeException(
120+
"Unable to marshall mapping JAXB representation to file `" + mappingXmlFile.getAbsolutePath() + "`",
121+
e);
122+
}
123+
catch (IOException e) {
124+
throw new RuntimeException(
125+
"Unable to format XML file `" + mappingXmlFile.getAbsolutePath() + "`",
126+
e);
127+
}
128+
}
129+
130+
private void performTransformation(
131+
List<Binding<JaxbHbmHibernateMapping>> hbmBindings,
132+
MappingBinder mappingBinder,
133+
ServiceRegistry serviceRegistry,
134+
boolean formatResult) {
135+
Marshaller marshaller = createMarshaller(mappingBinder);
136+
MetadataSources metadataSources = new MetadataSources( serviceRegistry );
137+
hbmBindings.forEach( metadataSources::addHbmXmlBinding );
138+
List<Binding<JaxbEntityMappingsImpl>> transformedBindings = HbmXmlTransformer.transform(
139+
hbmBindings,
140+
(MetadataImplementor) metadataSources.buildMetadata(),
141+
UnsupportedFeatureHandling.ERROR
142+
);
143+
for (int i = 0; i < hbmBindings.size(); i++) {
144+
Binding<JaxbHbmHibernateMapping> hbmBinding = hbmBindings.get( i );
145+
Binding<JaxbEntityMappingsImpl> transformedBinding = transformedBindings.get( i );
146+
HbmXmlOrigin origin = (HbmXmlOrigin)hbmBinding.getOrigin();
147+
File hbmXmlFile = origin.getHbmXmlFile();
148+
marshall(marshaller, transformedBinding.getRoot(), hbmXmlFile, formatResult);
149+
}
150+
}
151+
17152
}
Lines changed: 200 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,214 @@
11
package org.hibernate.tool.internal.export.mapping;
22

3-
import static org.junit.jupiter.api.Assertions.assertNotNull;
4-
3+
import jakarta.xml.bind.JAXBContext;
4+
import jakarta.xml.bind.Marshaller;
5+
import jakarta.xml.bind.Unmarshaller;
6+
import org.apache.commons.collections4.list.UnmodifiableList;
7+
import org.hibernate.boot.jaxb.Origin;
8+
import org.hibernate.boot.jaxb.internal.MappingBinder;
9+
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
10+
import org.hibernate.boot.jaxb.spi.Binding;
11+
import org.hibernate.boot.jaxb.spi.JaxbBindableMappingDescriptor;
12+
import org.hibernate.dialect.Dialect;
13+
import org.hibernate.engine.jdbc.spi.JdbcServices;
14+
import org.hibernate.service.ServiceRegistry;
15+
import org.hibernate.tool.internal.util.DummyDialect;
16+
import org.junit.jupiter.api.BeforeEach;
17+
import org.junit.jupiter.api.Disabled;
518
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.io.TempDir;
20+
21+
import java.io.File;
22+
import java.io.InputStream;
23+
import java.lang.reflect.*;
24+
import java.nio.file.Files;
25+
import java.util.ArrayList;
26+
import java.util.List;
27+
import java.util.Objects;
28+
29+
import static org.junit.jupiter.api.Assertions.*;
630

731
public class MappingExporterTest {
832

33+
private MappingExporter mappingExporter;
34+
35+
@TempDir
36+
private File tempDir;
37+
38+
@BeforeEach
39+
public void beforeEach() {
40+
mappingExporter = new MappingExporter();
41+
}
42+
43+
@Test
44+
public void testSetHbmFiles() throws NoSuchFieldException, IllegalAccessException {
45+
Field hbmFilesField = MappingExporter.class.getDeclaredField("hbmXmlFiles");
46+
List<File> origin = new ArrayList<>();
47+
File fooFile = new File( tempDir, "foo.bar" );
48+
origin.add( fooFile );
49+
assertNotNull(hbmFilesField);
50+
hbmFilesField.setAccessible(true);
51+
assertNull(hbmFilesField.get(mappingExporter));
52+
mappingExporter.setHbmFiles(origin);
53+
List<?> destination = (List<?>) hbmFilesField.get(mappingExporter);
54+
assertEquals(1, destination.size());
55+
assertTrue(destination.contains(fooFile));
56+
}
57+
58+
@Test
59+
public void testCreateServiceRegistry()
60+
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
61+
Method createServiceRegistryMethod = MappingExporter.class.getDeclaredMethod("createServiceRegistry");
62+
assertNotNull(createServiceRegistryMethod);
63+
createServiceRegistryMethod.setAccessible(true);
64+
Object object = createServiceRegistryMethod.invoke(mappingExporter);
65+
assertNotNull(object);
66+
assertInstanceOf(ServiceRegistry.class, object);
67+
try (ServiceRegistry serviceRegistry = (ServiceRegistry) object) {
68+
Dialect dialect = Objects.requireNonNull(serviceRegistry.getService(JdbcServices.class)).getDialect();
69+
assertInstanceOf(DummyDialect.class, dialect);
70+
}
71+
}
72+
73+
@Test
74+
public void testCreateMappingBinder()
75+
throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
76+
Method createMappingBinderMethod = MappingExporter.class.getDeclaredMethod("createMappingBinder");
77+
assertNotNull(createMappingBinderMethod);
78+
createMappingBinderMethod.setAccessible(true);
79+
Object object = createMappingBinderMethod.invoke(mappingExporter);
80+
assertNotNull(object);
81+
assertInstanceOf(MappingBinder.class, object);
82+
MappingBinder mappingBinder = (MappingBinder) object;
83+
assertNotNull(mappingBinder);
84+
}
85+
86+
@Test
87+
public void testBindMapping() throws Exception{
88+
Method bindMappingMethod = MappingExporter.class.getDeclaredMethod(
89+
"bindMapping",
90+
MappingBinder.class,
91+
HbmXmlOrigin.class);
92+
assertNotNull(bindMappingMethod);
93+
bindMappingMethod.setAccessible(true);
94+
File file = new File(this.tempDir, "foo.bar");
95+
Files.writeString(file.toPath(), "foobar");
96+
final MappingBinder mappingBinder = new TestMappingBinder(file, "barfoo");
97+
assertNotEquals("barfoo", Files.readString(file.toPath()));
98+
Object object = bindMappingMethod.invoke(mappingExporter, mappingBinder, new HbmXmlOrigin(file));
99+
assertInstanceOf(Binding.class, object);
100+
Origin origin = ((Binding<?>)object).getOrigin();
101+
assertInstanceOf(HbmXmlOrigin.class, origin);
102+
assertSame(file, ((HbmXmlOrigin)origin).getHbmXmlFile());
103+
assertEquals("barfoo", Files.readString(file.toPath()));
104+
}
105+
106+
@Test
107+
public void testGetHbmMappings() throws Exception {
108+
Method getHbmMappingsMethod = MappingExporter.class.getDeclaredMethod(
109+
"getHbmMappings",
110+
MappingBinder.class);
111+
assertNotNull(getHbmMappingsMethod);
112+
getHbmMappingsMethod.setAccessible(true);
113+
Field hbmFilesField = MappingExporter.class.getDeclaredField("hbmXmlFiles");
114+
hbmFilesField.setAccessible(true);
115+
List<File> hbmXmlFiles = new ArrayList<>();
116+
File file = new File(this.tempDir, "foo.bar");
117+
Files.writeString(file.toPath(), "foobar");
118+
hbmXmlFiles.add(file);
119+
hbmFilesField.set(mappingExporter, new UnmodifiableList<>(hbmXmlFiles));
120+
final MappingBinder mappingBinder = new TestMappingBinder(file, "barfoo");
121+
Object object = getHbmMappingsMethod.invoke(mappingExporter, mappingBinder);
122+
assertInstanceOf(List.class, object);
123+
assertEquals(1, ((List<?>)object).size());
124+
object = ((List<?>) object).get(0);
125+
assertInstanceOf(Binding.class, object);
126+
Origin origin = ((Binding<?>)object).getOrigin();
127+
assertInstanceOf(HbmXmlOrigin.class, origin);
128+
assertSame(file, ((HbmXmlOrigin)origin).getHbmXmlFile());
129+
assertEquals("barfoo", Files.readString(file.toPath()));
130+
}
131+
132+
@Test
133+
public void testCreateMarshaller() throws Exception {
134+
Method createMarshallerMethod = MappingExporter.class.getDeclaredMethod(
135+
"createMarshaller",
136+
MappingBinder.class);
137+
assertNotNull(createMarshallerMethod);
138+
createMarshallerMethod.setAccessible(true);
139+
final MappingBinder mappingBinder = new TestMappingBinder(new File("foo"), "foobar");
140+
assertSame(
141+
DUMMY_MARSHALLER,
142+
createMarshallerMethod.invoke(mappingExporter, mappingBinder));
143+
}
144+
145+
@Test
146+
public void testMarshall() throws Exception {
147+
Method marshallMethod = MappingExporter.class.getDeclaredMethod(
148+
"marshall",
149+
Marshaller.class,
150+
JaxbEntityMappingsImpl.class,
151+
File.class,
152+
boolean.class);
153+
assertNotNull(marshallMethod);
154+
marshallMethod.setAccessible(true);
155+
File hbmFile = new File(this.tempDir, "foo.hbm.xml");
156+
File mappingFile = new File(this.tempDir, "foo.mapping.xml");
157+
Files.writeString(mappingFile.toPath(), "<foo><bar>foobar</bar></foo>");
158+
List<String> lines = Files.readAllLines(mappingFile.toPath());
159+
assertEquals(1, lines.size());
160+
marshallMethod.invoke(mappingExporter, DUMMY_MARSHALLER, null, hbmFile, true);
161+
lines = Files.readAllLines(mappingFile.toPath());
162+
assertEquals(4, lines.size());
163+
}
164+
165+
@Disabled
9166
@Test
10167
public void testStart() {
11168
MappingExporter exporter = new MappingExporter();
12169
assertNotNull(exporter);
13170
exporter.start();
14171
}
15172

173+
private static final Marshaller DUMMY_MARSHALLER = (Marshaller) Proxy.newProxyInstance(
174+
MappingExporterTest.class.getClassLoader(),
175+
new Class<?>[]{Marshaller.class},
176+
(proxy, method, args) -> {
177+
if ("marshall".equals(method.getName())) {
178+
Files.writeString(((File)args[1]).toPath(), "foobar");
179+
}
180+
return proxy;
181+
}
182+
183+
);
184+
185+
private static class TestMappingBinder extends MappingBinder {
186+
private final File f;
187+
private final String s;
188+
public TestMappingBinder(File f, String s) {
189+
super(null, null, null);
190+
this.f = f;
191+
this.s = s;
192+
}
193+
@Override public <X extends JaxbBindableMappingDescriptor> org.hibernate.boot.jaxb.spi.Binding<X> bind(InputStream is, Origin o) {
194+
try {
195+
Files.writeString(f.toPath(), s);
196+
}
197+
catch (Exception ignore) {}
198+
return new Binding<>(null, new HbmXmlOrigin(f));
199+
}
200+
@Override public JAXBContext mappingJaxbContext() {
201+
return new JAXBContext() {
202+
@Override
203+
public Unmarshaller createUnmarshaller() {
204+
return null;
205+
}
206+
@Override
207+
public Marshaller createMarshaller() {
208+
return DUMMY_MARSHALLER;
209+
}
210+
};
211+
}
212+
}
213+
16214
}

0 commit comments

Comments
 (0)