beryx/badass-jlink-plugin

Create multiple tasks of type jlink

bjorndarri opened this issue · 2 comments

I have a project, in which I'd like to create two jlink images, each with a different runtime classpath.

I was hoping to be able to do this:

task jlinkJdbc(type: jlink) {
  imageName = 'client-jdbc'
  configuration = 'runtimeJdbc'

  ...
}

task jlinkRemote(type: jlink) {
  imageName = 'client-remote'
  configuration = 'runtimeRemote

  ...
}

But this does not appear to be supported:

Caused by: java.lang.ClassCastException: class org.beryx.jlink.data.JlinkPluginExtension_Decorated cannot be cast to class java.lang.Class (org.beryx.jlink.data.JlinkPluginExtension_Decorated is in unnamed module of loader org.gradle.internal.classloader.VisitableURLClassLoader @282fd0a5; java.lang.Class is in module java.base of loader 'bootstrap')
	at org.gradle.api.internal.tasks.DefaultTaskContainer.doCreate(DefaultTaskContainer.java:139)
	at org.gradle.api.internal.tasks.DefaultTaskContainer.create(DefaultTaskContainer.java:118)
	at org.gradle.api.internal.project.DefaultProject.task(DefaultProject.java:1293)
	at jdk.internal.reflect.GeneratedMethodAccessor164.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at org.gradle.internal.metaobject.BeanDynamicObject$MetaClassAdapter.invokeMethod(BeanDynamicObject.java:484)
	at org.gradle.internal.metaobject.BeanDynamicObject.tryInvokeMethod(BeanDynamicObject.java:196)
	at org.gradle.internal.metaobject.CompositeDynamicObject.tryInvokeMethod(CompositeDynamicObject.java:98)
	at org.gradle.internal.extensibility.MixInClosurePropertiesAsMethodsDynamicObject.tryInvokeMethod(MixInClosurePropertiesAsMethodsDynamicObject.java:34)
	at org.gradle.groovy.scripts.BasicScript$ScriptDynamicObject.tryInvokeMethod(BasicScript.java:135)
	at org.gradle.internal.metaobject.AbstractDynamicObject.invokeMethod(AbstractDynamicObject.java:163)
	at org.gradle.groovy.scripts.BasicScript.invokeMethod(BasicScript.java:84)

Am I perhaps overlooking something or is this simply not possible?

The short answer is that creating multiple tasks of type jlink is not supported.

The long answer is that in principle you should be able to do it, but it's quite tricky, because the plugin splits the operations required to create a custom runtime image in several tasks: prepareMergedJarsDir, createMergedModule, createDelegatingModules, prepareModulesDir, and jlink. So, you need to create custom tasks corresponding to each of the above tasks (i.e. tasks with type: PrepareMergedJarsDirTask, CreateMergedModuleTask, CreateDelegatingModulesTask, PrepareModulesDirTask, and JlinkTask).
The challenging part is to wire them together by setting the dependencies between them and by overriding the values of most of their properties. I expect to take quite a while to get this right.

Instead of fumbling with these tasks, you can try one of the following solutions:

  1. Create separate subprojects for each desired image, as in this example project, which creates two images: one using HSQLDB and one using H2. The application code is in app-main, while app-h2 and app-hsqldb are only tiny wrappers around it.

  2. Use a GradleRunner to execute the jlink task multiple times, each time with different properties, as in this example project.

Thank you, I'll be sure to try these out.