Gradle and Shadow plugin - copy additional files (.jar files) to final jar after shadowJar task
Asked Answered
K

1

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.

Krucik answered 27/9, 2018 at 1:23 Comment(4)
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?Mogul
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.Krucik
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).Mogul
@Mogul 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.Krucik
M
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.
Mogul answered 22/12, 2021 at 16:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.