9

Problem description:
I'm using Gradle Shade plugin, it all works fine and it copies resource files to the final jar. However, as the docs say, it can not include other .jar files as resources because it can not distinguish them from dependencies. It unpacks them isntead.

What I want to do:
I want to copy extra .jar files from tools folder (which lives next to my build.gradle) into the final jar produced by shadowJar task.

Question:
How to extend a task (shadowJar) to copy additional files into the produced jar file.

Dmitry Avtonomov
  • 8,747
  • 4
  • 32
  • 45
  • I think you need formulate the question more precise. Do you want to copy additional JARs *as is* to the shadow JAR (i.e. JAR files inside a JAR) or do you want to copy the *content* of additional JARs into the shadow JAR? – twwwt Dec 18 '21 at 22:06
  • I think the question stated precisely that I was able to copy any other resources, except jar files. "Contents of jar files" counts as "other resources". The question is about copying additional jars inside a fat jar. – Dmitry Avtonomov Dec 20 '21 at 06:32
  • I understand that your question "is about copying additional jars inside a fat jar". The point is, you can copy a JAR, say `j`, into an Uber JAR, say `u`, in two ways: either, the content of `j` is unpacked an copied into `u` (usually preserving the folder structure and in addition possibly merging `META-INF/services` files), or `j` is copied *as is* into `u` (i.e. the file itself in an unpacked way). – twwwt Dec 20 '21 at 14:47
  • @twwwt That's what I was trying to tell you. In your terminology, I want to copy a jar `J` into uber jar `U` **as-is (no unpacking)**. "Problem description" part of the question states that as well - it says that shadowJar unpacks the jars, instead of copying verbatim. I want `shadowJar` task to copy a jar `example.jar` from `some/path/example.jar` varbatim into `target/app-uberjar.jar`. – Dmitry Avtonomov Dec 21 '21 at 19:57

1 Answers1

0

This is answered in the documentation of the Gradle shadow plugin, section Embedding Jar Files Inside Your Shadow Jar:

[...] shadow is unable to distinguish between a jar file configured as a dependency and a jar file included in the resource folder. This means that any jar found in a resource directory will be merged into the shadow jar the same as any other dependency. If your intention is to embed the jar inside, you must rename the jar as to not end with .jar before the shadow task begins.

Unfortunately, this holds both for a JAR that is part of a dependency configuration as well as copying a JAR using a from copy spec (which works since the shadowJar task extends the jar task; which in turn is a copy task and hence supports copy specs).

So, a JAR can only be embedded by renaming it. If it must be named .jar inside the Uber JAR, I think the only option is a three-step workaround:

  1. Create the Uber JAR and embed JARs by renaming them; e.g., use the suffix *.zip.
shadowJar
{
    from("${dirThatContainsSomeJARs}")
    {
        include '*.jar'
        rename '(.+).jar', '$1.zip'
    }
}
  1. Unpack the Uber JAR and rename all JARs that have been embedded as *.zip back to *.jar.
  2. Repack everything again using the jar or zip task.
twwwt
  • 438
  • 1
  • 4
  • 16