Spring-boot: Rework Gradle plugin's repackaging support to be more idiomatic

Created on 4 May 2016  ·  3Comments  ·  Source: spring-projects/spring-boot

The Gradle plugin's current support for repackaging a jar to create a fat executable jar is, pretty much, a direct conversion of the equivalent functionality in the Maven plugin. As such, it could be a better Gradle citizen than it is at the moment.

  1. The current RepackageTask figures out what it should do, rather than being configured by the plugin. This makes the task hard to reuse. The plugin should provide a default, pre-configured task for producing a fat jar.
  2. The current RepackageTask doesn't declare its inputs and outputs in a conventional manner. This means that Gradle's up-to-date checking doesn't work as it should. For example, changing the embedded launch script properties won't cause the fat jar to be rebuilt. The task should be updated to fully declare all of its inputs and outputs by using the relevant @Input and @Output… annotations.
  3. Related to 1, too much of the repackaging configuration is exposed via the Spring Boot plugin extension. The task currently looks at the extension to determine its own configuration. The alternative is for the plugin to pass the extensions settings through to the repackaging task, but this makes things complicated as it should only pass through the extension's configuration when the user hasn't configured it directly on the task. We could dramatically simplify this by removing almost all of the configuration options from the extension.
  4. Related to 1 and 2, preconfiguring the repackaging task makes the find main class task useless. If it's going to be set, the main class for repackaging needs to be configured as an input of the task. That means setting it before compilation has been performed so, therefore, it can't be auto-detected. It either needs to be set explicitly by the user, or the Repackager needs to be left to resolve it from the jar's byte code.
  5. By default, repackaging overwrites the jar artifact. This means that the jar task will never be up-to-date and will always be re-run. The default should be to write the repackaged jar to a different location.
  6. The task dependencies for repackaging are far too broad – for example, they currently include all the build dependencies of every artifact in the archives configuration. Repackaging should depend solely on the jar/war that's being repackaged and the configurations that contain the dependencies that are to be included in the jar. (#2622, #3931, #5259)
  7. The assemble task is explicitly configured to depend on the repackaging task. The assemble task is automatically configured to depend on everything that builds an artifact that's part of the archives configuration. If we want the task to run on assemble, it should publish such an artifact.
  8. It's harder than it needs to be to publish a repackaged fat jar. A software component should be declared which exposes the fat jar artifact, configured to have no dependencies (just like a war). We may want to hold off on this part as the functionality is marked as incubating. (#1666)
  9. Related to 1, unless configured to repackage the output of a particular jar or war task, the repackage task will repackage the output of every jar or war task. This makes the process of configuring its outputs rather complicated and that process is buggy at the moment (#5393). We should creating a single fat jar or war per repackaging task.

As part of addressing all of the above, I think we should consider not actually repackaging an existing jar or war file. Instead, we should have BootJar and BootWar tasks that are subclasses of Gradle's Jar and War tasks respectively. They will use the appropriate source set's output as (part of) their input. This should make it significantly easier to configure task dependencies. It will also make it easier to address 7 and 8 as it's trivial to create a PublishArtifact from an AbstractArchiveTask subclass. This is the approach taken by the shadow plugin and its ShadowJar.

enhancement

Most helpful comment

Yes, please become a nicer gradle citizen (just got bitten by the fact that bootRepackage does not properly expose the output filename...)

All 3 comments

Might I suggest that it would be nice to be able to get the path to the repackaged file somehow? The use case: I generate Cloud Foundry's manifest.yml to include the path attribute to point to the generated file. Right now I rely on the fact that the name is the same as the jar task's output as long I don't use any classifier. I would like to use one, though, as the repackage task wouldn't then force gradle to re-run jar again and again.
I guess if you subclass the default JarTask, this feature will be available for free. If not, would you consider exposing the generated file path somehow?

Yes, please become a nicer gradle citizen (just got bitten by the fact that bootRepackage does not properly expose the output filename...)

👍 for @otrosien 's use case (getting the jar file for CF), although some of this could probably be handled by cf accepting patterns.

Was this page helpful?
0 / 5 - 0 ratings