'How to enable Eclipselink's static weaving from Gradle
I'd like to enable Eclipselink's static weaving for my JPA classes from Gradle. The Eclipselink docs explain how to do this in an Ant task:
<target name="define.task" description="New task definition for EclipseLink static weaving"/>
<taskdef name="weave" classname="org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask"/>
</target>
<target name="weaving" description="perform weaving" depends="define.task">
<weave source="c:\myjar.jar"
target="c:\wovenmyjar.jar"
persistenceinfo="c:\myjar-containing-persistenceinfo.jar">
<classpath>
<pathelement path="c:\myjar-dependent.jar"/>
</classpath>
</weave>
</target>
Now I've got 2 questions:
1. How do I 'translate' this into a Gradle approach? I've tried this (based on the docs at http://www.gradle.org/docs/current/userguide/ant.html#N1143F):
task eclipseWeave << {
ant.taskdef(name: "weave",
classname: "org.eclipse.persistence.tools.weaving.jpa.StaticWeaveAntTask",
classpath: configurations.compile.asPath)
ant.weave(source: relativePath(compileJava.destinationDir),
target: relativePath(compileJava.destinationDir),
persistenceinfo: relativePath(processResources.destinationDir) {
}
}
but the problem is that the classpath doesn't seem to work within ant.weave(..). The weaving process is aborted after a bit with the message:
Execution failed for task ':eclipseWeave'.
> java.lang.NoClassDefFoundError: some/class/from/my/dependencies
The classpath setting works for ant.taskdef(..) since the StaticWeaveAntTask is found in my dependencies. How can I make it apply to ant.weave(..) itself?
2. How do I integrate this into my build, so it is executed automatically after each compileJava step?
Solution 1:[1]
I know this is an old question, but based on the OP's comment for the "gradle" way to do it, I thought I'd share our approach. We are using the JavaExec task and the various available configuration objects.
Since the weaving is done in the classes directory (before the JAR is built) you end up only having to build one jar, not two. Since our jar is quite large, that was important to us.
task performJPAWeaving(type: JavaExec, dependsOn: "compileJava"){
inputs.dir compileJava.destinationDir
outputs.dir compileJava.destinationDir
main "org.eclipse.persistence.tools.weaving.jpa.StaticWeave"
args "-persistenceinfo",
"src/main/resources",
compileJava.destinationDir.getAbsolutePath()
classpath = configurations.compileClasspath
}
tasks.withType(Jar){
dependsOn "performJPAWeaving"
}
Solution 2:[2]
Problem description
I had a similar issue and would like to share my solution which is based on the previous post. Following problems were solved:
- Process persistence.xml and replace tokens before weaving.
- Find a workaround for this known EclipseLink Weaver bug which prevents using the Weavers -persistenceunit flag with Gradle.
- Discover entitiy classes automatically instead of listing them in persistence.xml.
Step 1: Process persistence.xml
Firstly, the placeholder @datasourceName@ should be replaced with an actual value. This is achieved through following snipped in your build.gradle file:
import org.apache.tools.ant.filters.ReplaceTokens
ext {
dsName = 'MyDataSourceName'
puName = 'MyPuName'
}
processResources {
filter(ReplaceTokens, tokens: [
datasourceName: dsName,
persistenceUnitName: puName
])
}
Following code shows the (simplified) src/main/resources/META-INF/persistence.xml file:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="@datasourceName@" transaction-type="JTA">
<jta-data source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=@datasourceName@)</jta-data-source>
<!-- Necessary to let EclipseLink/Weaver discover local classes without listing them in this file,
see http://www.eclipse.org/eclipselink/documentation/2.7/concepts/app_dev001.htm#BGBHFFAG-->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<!-- Tell the application container that our classes are already woven,
see https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving-->
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
It's important to mention, that the flag exclude-unlisted-classes must be set to false in order to make the EclipseLink Weaver discovering the annotated entity classes automatically. Make also sure, that the property "eclipselink.weaving" is set to "static" which tells your application runtime, that the entity classes are already woven and do not need to be enhanced dynamically. If you work with OSGi, keep in mind to import all necessary EclipseLink packages into the bundle which contains the woven classes.
After the processResources task has been executed, the generated file build/resources/main/META-INF/persistence.xml looks like this (note the persistence-unit name):
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="MyPuName" transaction-type="JTA">
<jta-data-source>osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=MyDataSourceName)</jta-data-source>
<!-- Necessary to let EclipseLink/Weaver discover local classes without listing them in this file,
see http://www.eclipse.org/eclipselink/documentation/2.7/concepts/app_dev001.htm#BGBHFFAG -->
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<!-- Tell the application container that our classes are already woven,
see, https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving-->
<property name="eclipselink.weaving" value="static" />
</properties>
</persistence-unit>
Step 2: Copy the generated persistence.xml
Next, we add a new Copy task which copies the processed resources into the output directory of the compileJava task. This is necessary to have all necessary artifacts on the Weavers classpath (works around bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=295031). Add following task to your build.gradle file:
task copyResourcesToClassesOutputDir(type: Copy, dependsOn: processResources) {
from processResources.destinationDir
into compileJava.destinationDir
}
Step 3: Weave your entity classes
In order to enhance your classes, it's necessary to configure your build appropriately. Add following snipped to your build.gradle. A separate classpath configuration has been declared because having the EclipseLink classes in the ordinary compile classpath is not desired.
configurations {
providedApi
}
dependencies {
providedApi 'org.eclipse.persistence:org.eclipse.persistence.jpa:2.7.2'
providedApi 'org.eclipse.persistence:javax.persistence:2.2.0'
}
task performJPAWeaving(type: JavaExec) {
main "org.eclipse.persistence.tools.weaving.jpa.StaticWeave"
args "-loglevel",
"FINE",
compileJava.destinationDir.absolutePath,
compileJava.destinationDir.absolutePath
classpath (configurations.compile, configurations.providedApi)
dependsOn compileJava
dependsOn copyResourcesToClassesOutputDir
}
// Do always weave the classes before a JAR is created
tasks.withType(Jar) {
dependsOn "performJPAWeaving"
}
That's it! If you run now any Jar task, your entity classes will be enhanced before they are packed into the Jar file.
Solution 3:[3]
None of the other answers worked for me very well (possibly because of changes to Gradle - I'm using v7.4). I ended up copying my persistence.xml (with <exclude-unlisted-classes>false</exclude-unlisted-classes> in it) into my classes directory and then running the EclipseLink Weaver. I put it as part for doLast for the Java Compile which I think will allow Gradle to cache compilation in the normal way (although I'm not fully clear on this) - the alternative is before the Jar task but I want to make sure that local behaviour is identical to deployed behaviour for things like lazy loading.
tasks.withType(JavaCompile) {
doLast {
def path = sourceSets.main.compileClasspath
def listOfUrls = path.collect {f -> f.toURI().toURL()} as URL[]
def loader = new URLClassLoader(listOfUrls)
//Finding classes only works from the root containing persistence.xml containing directory downwards
def xmlContents = new File(sourceSets.main.resources.srcDirs.iterator().next(), 'META-INF/persistence.xml').text
def tempDir = new File(sourceSets.main.output.classesDirs.singleFile, 'META-INF')
tempDir.mkdirs()
def tempFile = new File(tempDir, 'persistence.xml')
tempFile.delete()
tempFile << xmlContents
xmlContents = null
def proc = new org.eclipse.persistence.tools.weaving.jpa.StaticWeaveProcessor(
sourceSets.main.output.classesDirs.singleFile,
sourceSets.main.output.classesDirs.singleFile
)
proc.setLogLevel(5)
proc.setClassLoader(loader)
proc.setPersistenceInfo(sourceSets.main.output.classesDirs.singleFile)
proc.performWeaving()
tempFile.delete()
tempDir.delete()
}
}
You also have to have org.eclipse.persistence:org.eclipse.persistence.jpa as a script dependency - for me that meant adding it to buildSrc/build.gradle but for others it might mean adding a classpath entry to your buildscript dependencies like you do with Legacy plugins.
I'm not happy with how I find the persistence.xml file - I'm sure there's a better way but it works for me for now and I've spent too long on this!
Solution 4:[4]
Kinda late to the party but this is possible very easily with Gradle, you just need to think it through.
There are 3 steps to do in order to make this work:
- Copy the persistence.xml file into the source folder next to the classes
- Do the weaving
- Remove the
persistence.xmlfile from the classes source folder to avoid duplicatepersistence.xmlconflicts on the classpath
Also, it's very important to hook the process up into the compileJava task's last step in order to not break Gradle's up-to-date check, otherwise you can end up in a situation where Gradle will always recompile your code no matter nothing has changed.
For a more detailed explanation, check out my article on it: EclipseLink static weaving with Gradle.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | mjaggard |
| Solution 4 | Arnold Galovics |
