Skip to content

Commit 6e9ca7c

Browse files
committed
HHH-19638: Document the Ant enhancement task in User Guide tooling section
- Create a test for 'org.hibernate.tool.enhance.EnhancementTask' that covers all the configuration settings Signed-off-by: Koen Aers <[email protected]>
1 parent 9c01bf5 commit 6e9ca7c

File tree

5 files changed

+414
-1
lines changed

5 files changed

+414
-1
lines changed

tooling/hibernate-ant/hibernate-ant.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ plugins {
88
description = 'Annotation Processor to generate JPA 2 static metamodel classes'
99

1010
dependencies {
11-
compileOnly libs.ant
11+
implementation libs.ant
1212
implementation project( ':hibernate-core' )
1313
}
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.tool.enhance;
6+
7+
import org.apache.tools.ant.DefaultLogger;
8+
import org.apache.tools.ant.Project;
9+
import org.apache.tools.ant.ProjectHelper;
10+
import org.hibernate.bytecode.enhance.spi.EnhancementInfo;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.jupiter.api.io.TempDir;
14+
15+
import java.io.File;
16+
import java.lang.reflect.Field;
17+
import java.lang.reflect.Method;
18+
import java.net.URL;
19+
import java.net.URLClassLoader;
20+
import java.nio.file.Files;
21+
import java.util.List;
22+
23+
import static org.junit.jupiter.api.Assertions.assertFalse;
24+
import static org.junit.jupiter.api.Assertions.assertTrue;
25+
26+
public class EnhancementTaskTest {
27+
28+
@TempDir
29+
private File projectDir;
30+
31+
@BeforeEach
32+
public void beforeEach() throws Exception {
33+
copyJavFiles();
34+
prepareDestFolder();
35+
}
36+
37+
@Test
38+
public void testEnhancementDefault() throws Exception {
39+
// The default settings for the enhancement task are as follows:
40+
// enableLazyInitialization = 'true'
41+
// enableDirtyTracking = 'true'
42+
// enableAssociationManagement = 'false'
43+
// enableExtendedEnhancement = 'false'
44+
// The files are read from folder 'dir' which needs to be a subfolder of 'base'
45+
// The property 'base' is mandatory
46+
// If 'dir' is not specified, a 'fileset' element can be used (see #testEnhancementFileSet)
47+
String enhanceTag =
48+
"<enhance base='${basedir}/dest' dir='${basedir}/dest'/>\n";
49+
Project project = createProject(enhanceTag);
50+
executeCompileTarget( project );
51+
executeEnhanceTarget( project );
52+
// Both Bar and Baz should be enhanced
53+
assertTrue(isEnhanced( "Bar" ));
54+
assertTrue(isEnhanced( "Baz" ));
55+
// Both Bar and Baz contain the method '$$_hibernate_getInterceptor'
56+
// because of the default setting of 'enableLazyInitialization'
57+
assertTrue( methodIsPresentInClass("$$_hibernate_getInterceptor", "Bar"));
58+
assertTrue( methodIsPresentInClass("$$_hibernate_getInterceptor", "Baz"));
59+
// Both Bar and Baz contain the method '$$_hibernate_hasDirtyAttributes'
60+
// because of the default setting of 'enableDirtyTracking'
61+
assertTrue( methodIsPresentInClass("$$_hibernate_hasDirtyAttributes", "Bar"));
62+
assertTrue( methodIsPresentInClass("$$_hibernate_hasDirtyAttributes", "Baz"));
63+
// Foo is not an entity and extended enhancement is not enabled so the class is not enhanced
64+
assertFalse(isEnhanced("Foo"));
65+
// Association management should not be present
66+
assertFalse(isAssociationManagementPresent());
67+
}
68+
69+
@Test
70+
public void testEnhancementFileSet() throws Exception {
71+
// Use the defaults settings for enhancement (see #testEnhancementDefault)
72+
// The property 'base' is mandatory
73+
// The files are read from the specified 'fileset' element:
74+
// - the folder specified by 'dir'
75+
// - the 'Baz.class' file is excluded
76+
String enhanceTag =
77+
"<enhance base='${basedir}/dest'>\n" +
78+
" <fileset dir='${basedir}/dest'>\n" +
79+
" <exclude name='Baz.class' />\n" +
80+
" </fileset>\n" +
81+
"</enhance>\n";
82+
Project project = createProject(enhanceTag);
83+
executeCompileTarget(project);
84+
executeEnhanceTarget(project);
85+
// Bar is enhanced
86+
assertTrue(isEnhanced( "Bar" ));
87+
// Baz is not enhanced because it was excluded from the file set
88+
assertFalse(isEnhanced( "Baz" ));
89+
// Foo is not enhanced because it is not an entity and extended enhancement was not enabled
90+
assertFalse( isEnhanced( "Foo" ) );
91+
// Association management should not be present
92+
assertFalse(isAssociationManagementPresent());
93+
}
94+
95+
@Test
96+
public void testEnhancementNoLazyInitialization() throws Exception {
97+
// Change the default setting for 'enableLazyInitialization' to 'false'
98+
// Otherwise use the settings of #testEnhancementDefault
99+
String enhanceTag =
100+
"<enhance \n" +
101+
" base='${basedir}/dest'\n" +
102+
" dir='${basedir}/dest'\n" +
103+
" enableLazyInitialization='false'/>\n";
104+
Project project = createProject(enhanceTag);
105+
executeCompileTarget(project);
106+
executeEnhanceTarget(project);
107+
// Both Bar and Baz are enhanced, Foo is not
108+
assertTrue( isEnhanced( "Bar" ));
109+
assertTrue( isEnhanced( "Baz" ));
110+
// Foo is not enhanced because it is not an entity and extended enhancement was not enabled
111+
assertFalse( isEnhanced( "Foo" ) );
112+
// but $$_hibernate_getInterceptor is not present in the enhanced classes
113+
// because of the 'false' value of 'enableLazyInitialization'
114+
assertFalse( methodIsPresentInClass("$$_hibernate_getInterceptor", "Bar"));
115+
assertFalse( methodIsPresentInClass("$$_hibernate_getInterceptor", "Baz"));
116+
// Association management should not be present
117+
assertFalse(isAssociationManagementPresent());
118+
}
119+
120+
@Test
121+
public void testEnhancementNoDirtyTracking() throws Exception {
122+
// Change the default setting for 'enableDirtyTracking' to 'false'
123+
// Otherwise use the settings of #testEnhancementDefault
124+
String enhanceTag =
125+
"<enhance \n" +
126+
" base='${basedir}/dest'\n" +
127+
" dir='${basedir}/dest'\n" +
128+
" enableDirtyTracking='false'/>\n";
129+
Project project = createProject(enhanceTag);
130+
executeCompileTarget(project);
131+
executeEnhanceTarget(project);
132+
// Both Bar and Baz should be enhanced
133+
assertTrue( isEnhanced( "Bar" ));
134+
assertTrue( isEnhanced( "Baz" ));
135+
// Foo is not enhanced because it is not an entity and extended enhancement was not enabled
136+
assertFalse( isEnhanced( "Foo" ) );
137+
// $$_hibernate_hasDirtyAttributes is not present in the enhanced classes
138+
// because of the 'false' value of 'enableLazyInitialization'
139+
assertFalse( methodIsPresentInClass("$$_hibernate_hasDirtyAttributes", "Bar"));
140+
assertFalse( methodIsPresentInClass("$$_hibernate_hasDirtyAttributes", "Baz"));
141+
// Association management should not be present
142+
assertFalse(isAssociationManagementPresent());
143+
}
144+
145+
@Test
146+
public void testEnhancementEnableAssociationManagement() throws Exception {
147+
// Change the default setting for 'enableAssociationManagement' to 'true'
148+
// Otherwise use the settings of #testEnhancementDefault
149+
String enhanceTag =
150+
"<enhance \n" +
151+
" base='${basedir}/dest'\n" +
152+
" dir='${basedir}/dest'\n" +
153+
" enableAssociationManagement='true'/>\n";
154+
Project project = createProject(enhanceTag);
155+
executeCompileTarget(project);
156+
executeEnhanceTarget(project);
157+
// Both Bar and Baz are enhanced, Foo is not
158+
assertTrue( isEnhanced( "Bar" ));
159+
assertTrue( isEnhanced( "Baz" ));
160+
assertFalse( isEnhanced( "Foo" ) );
161+
// Now verify that the association management is in place;
162+
assertTrue(isAssociationManagementPresent());
163+
}
164+
165+
@Test
166+
public void testEnhancementEnableExtendedEnhancement() throws Exception {
167+
// Change the default setting for 'enableExtendedEnhancement' to 'true'
168+
// Otherwise use the settings of #testEnhancementDefault
169+
String enhanceTag =
170+
"<enhance \n" +
171+
" base='${basedir}/dest'\n" +
172+
" dir='${basedir}/dest'\n" +
173+
" enableExtendedEnhancement='true'/>\n";
174+
Project project = createProject(enhanceTag);
175+
executeCompileTarget(project);
176+
executeEnhanceTarget(project);
177+
// Both Bar and Baz are enhanced because they are entities
178+
assertTrue( isEnhanced( "Bar" ));
179+
assertTrue( isEnhanced( "Baz" ));
180+
// Though Foo is not an entity, it is enhanced because of the setting of 'enableExtendedEnhancement'
181+
assertTrue( isEnhanced( "Foo" ) );
182+
// No association management is in place;
183+
assertFalse(isAssociationManagementPresent());
184+
}
185+
186+
@Test
187+
public void testNoEnhancement() throws Exception {
188+
// Setting the values of all the settings to 'false' has the effect
189+
// of not executing the enhancement at all.
190+
// The setting of 'enableAssociationManagement' and 'enableExtendedEnhancement' to
191+
// false is not really needed in this case as that's what their default is
192+
String enhanceTag =
193+
"<enhance \n" +
194+
" base='${basedir}/dest'\n" +
195+
" dir='${basedir}/dest'\n" +
196+
" enableLazyInitialization='false'\n" +
197+
" enableDirtyTracking='false'\n" +
198+
" enableAssociationManagement='false'\n" +
199+
" enableExtendedEnhancement='false'/>\n";
200+
Project project = createProject(enhanceTag);
201+
executeCompileTarget(project);
202+
executeEnhanceTarget(project);
203+
// None of the classes should be enhanced
204+
assertFalse( isEnhanced( "Bar" ));
205+
assertFalse( isEnhanced( "Baz" ));
206+
assertFalse( isEnhanced( "Foo" ) );
207+
// No association management is in place;
208+
assertFalse(isAssociationManagementPresent());
209+
}
210+
211+
private boolean isAssociationManagementPresent() throws Exception {
212+
// Some dynamic programming
213+
ClassLoader loader = getTestClassLoader();
214+
// Obtain the class objects for 'Baz' and 'Bar'
215+
Class<?> bazClass = loader.loadClass( "Baz" );
216+
Class<?> barClass = loader.loadClass( "Bar" );
217+
// Create an instance of both 'Baz' and 'Bar'
218+
Object bazObject = bazClass.getDeclaredConstructor().newInstance();
219+
Object barObject = barClass.getDeclaredConstructor().newInstance();
220+
// Lookup the 'bars' field of class 'Baz' (an ArrayList of 'Bar' objects)
221+
Field bazBarsField = bazClass.getDeclaredField( "bars" );
222+
bazBarsField.setAccessible( true );
223+
// Obtain the 'bars' list of the 'Baz' object; it should be empty
224+
List<?> bazBarsList = (List<?>) bazBarsField.get( bazObject ); // baz.bars
225+
assertTrue(bazBarsList.isEmpty());
226+
// Lookup the 'setBaz' method of class 'Bar' and invoke it on the 'Bar' object
227+
Method barSetBazMethod = barClass.getDeclaredMethod( "setBaz", new Class[] { bazClass } );
228+
barSetBazMethod.invoke( barObject, bazObject ); // bar.setBaz(baz)
229+
// Reobtain the 'bars' list of the 'Baz' object
230+
bazBarsList = (List<?>) bazBarsField.get( bazObject );
231+
// If there is association management, the 'bars' list should contain the 'Bar' object
232+
return bazBarsList.contains( barObject ); // baz.bars.contains(bar)
233+
}
234+
235+
private Project createProject(String enhanceTag) throws Exception {
236+
File buildXmlFile = createBuildXmlFile(enhanceTag);
237+
Project result = new Project();
238+
result.setBaseDir(projectDir);
239+
result.addBuildListener(createConsoleLogger());
240+
ProjectHelper.getProjectHelper().parse(result, buildXmlFile);
241+
return result;
242+
}
243+
244+
private void executeCompileTarget(Project project) {
245+
// The class files should not exist
246+
assertFalse(fileExists("dest/Bar.class"));
247+
assertFalse(fileExists("dest/Baz.class"));
248+
assertFalse(fileExists("dest/Foo.class"));
249+
// Execute the 'compile' target
250+
project.executeTarget( "compile" );
251+
// The class files should exist now
252+
assertTrue( fileExists( "dest/Bar.class" ) );
253+
assertTrue( fileExists( "dest/Baz.class" ) );
254+
assertTrue( fileExists( "dest/Foo.class" ) );
255+
}
256+
257+
private void executeEnhanceTarget(Project project) throws Exception {
258+
// The class files should not be enhanced at this point
259+
assertFalse( isEnhanced( "Bar" ));
260+
assertFalse( isEnhanced( "Baz" ));
261+
assertFalse( isEnhanced( "Foo" ));
262+
// Execute the 'enhance' target
263+
project.executeTarget( "enhance" );
264+
// The results are verified in the respective tests
265+
}
266+
267+
private File createBuildXmlFile(String enhanceTag) throws Exception {
268+
File result = new File( projectDir, "build.xml" );
269+
assertFalse(result.exists());
270+
Files.writeString(
271+
result.toPath(),
272+
BUILD_XML_TEMPLATE.replace( "@enhanceTag@", enhanceTag ) );
273+
assertTrue( result.exists() );
274+
assertTrue(result.isFile());
275+
return result;
276+
}
277+
278+
private DefaultLogger createConsoleLogger() {
279+
DefaultLogger consoleLogger = new DefaultLogger();
280+
consoleLogger.setErrorPrintStream(System.err);
281+
consoleLogger.setOutputPrintStream(System.out);
282+
consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
283+
return consoleLogger;
284+
}
285+
286+
private boolean fileExists(String relativePath) {
287+
return new File( projectDir, relativePath ).exists();
288+
}
289+
290+
private void prepareDestFolder() {
291+
File destFolder = new File(projectDir, "dest");
292+
assertFalse( destFolder.exists() );
293+
assertTrue( destFolder.mkdir() );
294+
assertTrue( destFolder.exists() );
295+
assertTrue( destFolder.isDirectory() );
296+
}
297+
298+
private boolean isEnhanced(String className) throws Exception {
299+
return getTestClassLoader().loadClass( className ).isAnnotationPresent( EnhancementInfo.class );
300+
}
301+
302+
private boolean methodIsPresentInClass(String methodName, String className) throws Exception {
303+
Class<?> classToCheck = getTestClassLoader().loadClass( className );
304+
try {
305+
Object m = classToCheck.getMethod( methodName, new Class[] {} );
306+
return true;
307+
} catch (NoSuchMethodException e) {
308+
return false;
309+
}
310+
}
311+
312+
private ClassLoader getTestClassLoader() throws Exception {
313+
return new URLClassLoader( new URL[] { new File(projectDir, "dest").toURI().toURL() } );
314+
}
315+
316+
private void copyJavFiles() throws Exception {
317+
File srcDir = new File(projectDir, "src");
318+
srcDir.mkdir();
319+
String[] javFileNames = {"Bar.jav_", "Baz.jav_", "Foo.jav_"};
320+
for (String javFileName : javFileNames) {
321+
copyJavFile( javFileName, srcDir );
322+
}
323+
}
324+
325+
private void copyJavFile(String javFileName, File toFolder) throws Exception {
326+
URL url = getClass().getClassLoader().getResource( javFileName );
327+
assert url != null;
328+
File source = new File(url.toURI());
329+
File destination = new File(toFolder, javFileName.replace( '_', 'a' ));
330+
assertTrue(source.exists());
331+
assertTrue(source.isFile());
332+
Files.copy(source.toPath(), destination.toPath());
333+
assertTrue(destination.exists());
334+
assertTrue(destination.isFile());
335+
}
336+
337+
private static String BUILD_XML_TEMPLATE =
338+
"<project>\n" +
339+
" <taskdef \n" +
340+
" name='enhance'\n" +
341+
" classname='org.hibernate.tool.enhance.EnhancementTask'/>\n" +
342+
" <target name='compile'>\n" +
343+
" <javac srcdir='src' destdir='dest' includeantruntime='true' />\n" +
344+
" </target>\n" +
345+
" <target name='enhance'>\n" +
346+
" @enhanceTag@\n" +
347+
" </target>\n" +
348+
"</project>";
349+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import jakarta.persistence.Entity;
2+
import jakarta.persistence.ManyToOne;
3+
4+
@Entity
5+
public class Bar {
6+
7+
private String foo;
8+
9+
@ManyToOne
10+
private Baz baz;
11+
12+
public String getFoo() {
13+
return foo;
14+
}
15+
16+
public void setFoo(String f) {
17+
foo = f;
18+
}
19+
20+
public Baz getBaz() { return baz; }
21+
22+
public void setBaz(Baz baz) { this.baz = baz; }
23+
24+
}

0 commit comments

Comments
 (0)