Shadow Plugin Gradle: What does mergeServiceFiles() do?
Asked Answered
P

2

24

In my build.gradle file I need to add the line:

shadowJar {
    mergeServiceFiles()
}

Otherwise the jar does not run properly. I wonder what this line does exactly? I use the Gradle plugin in Eclipse Luna. I create the jar on one Java project which depends on another one.

Papagena answered 1/10, 2015 at 12:46 Comment(0)
Q
13

mergeServiceFiles is declared exactly here and its implementation is as follows:

/**
 * Syntactic sugar for merging service files in JARs
 * @return
 */
public ShadowJar mergeServiceFiles() {
    try {
        transform(ServiceFileTransformer.class);
    } catch (IllegalAccessException e) {
    } catch (InstantiationException e) {
    }
    return this;
}

As you can see it uses ServiceFileTransfomer which is defined here. From its docs:

Modified from org.apache.maven.plugins.shade.resource.ServiceResourceTransformer.java

Resources transformer that appends entries in META-INF/services resources into a single resource. For example, if there are several META-INF/services/org.apache.maven.project.ProjectBuilder resources spread across many JARs the individual entries will all be concatenated into a single META-INF/services/org.apache.maven.project.ProjectBuilder resource packaged into the resultant JAR produced by the shading process.

Quincuncial answered 2/10, 2015 at 7:19 Comment(0)
K
5

TL;DR - It merges the service files in the META-INF/services folder.

Long Answer

Some libraries (e.g. Micronaut) create a few service files in the META-INF/services folder. These files can contain any information useful at runtime. In case of Micronaut framework, it creates a file that lists the Bean References (or beans that are instantiated) in a file called io.micronaut.inject.BeanDefinitionReference under META-INF/services.

Usually, if you just have one application, it works fine even without mergeServiceFiles(). But if there are two micronaut projects that you are bundling into a single jar (e.g. a micronaut lib project with some utils and a micronaut app project with core business logic), you will have two io.micronaut.inject.BeanDefinitionReference. Each one will contain the beans of it's own project.

If you don't use mergeServiceFiles(), one of the BeanDefinitionReference files will be overwritten by the other. In that case, you will get a runtime exception saying BeanNotInstantiated or something of that sort.

Using mergeServiceFiles() merges (or concatenates in this case) the BeanDefinitionReference files of both the projects so that at runtime, you get all the beans defined.

More details can be found in the gradle forum topic here.

Kerouac answered 7/4, 2021 at 13:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.