Skip to content

worace/multi-jar-vs-uberjar-resources

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
app
 
 
 
 
 
 
 
 
 
 
 
 

Multi JAR vs. Uberjar Handling of Resource Conflicts

This is an example project to complement an article on JVM Deployment Strategies.

It shows an example of dealing with a resource file collision between 2 libraries in an Uberjar vs. Multi JAR context.

Project Structure:

tree .
.
├── app
│   ├── build.sbt
│   ├── project
│   │   ├── build.properties
│   │   ├── plugins.sbt
│   │   └── project
│   └── src
│       └── main
│           └── scala
│               └── com
│                   └── example
│                       └── App.scala
├── lib-a
│   ├── build.sbt
│   ├── project
│   │   └── build.properties
│   └── src
│       └── main
│           ├── resources
│           │   └── pizza.txt
│           └── scala
│               └── com
│                   └── example
│                       └── liba
│                           └── LibA.scala
├── lib-b
│   ├── build.sbt
│   ├── project
│   │   └── build.properties
│   └── src
│       └── main
│           ├── resources
│           │   └── pizza.txt
│           └── scala
│               └── com
│                   └── example
│                       └── libb
│                           └── LibB.scala
├── README.md
└── script.sh

26 directories, 14 files

./app is a very simple example application, and lib-a and lib-b are example libraries that we simulate by publishing them into the local Ivy cache.

./script.sh is a test script which publishes the 2 libraries locally, runs the app project via sbt (multi JAR Classpath) and then attempts to build an uberjar from it.

Takeaways

The problem of resource collisions (i.e. 2 JARs containing resources of the same file name) doesn't go away when using a multi-JAR classpath configuration. Rather, you will simply silently get one of them at runtime (probably the first one) with others being ignored.

Building an uberjar has the benefit of moving this problem to build time, and ideally warning you about it in some way (for example the sbt-assembly plugin throws an error on this collision if you don't handle it).

Loading Single vs. Multi Resources

Like most people I have usually used the public URL getResource(String name) API on java.lang.Class. This returns a single URL to a resource from the classpath, relying on the "first one wins" behavior described above.

A reddit user also pointed out the public Enumeration<URL> getResources(String name) API on java.lang.ClassLoader. This gives a list of resources matching a filename. However I think in practice it can be tricky to work with the URLs as they point to nested paths within Zipped JAR archives.

Example Run Output

./script.sh
*** Running Example Script ***


*** Publishing lib-a to local ~/.ivy2 ***
# ...
[info]  published ivy to /home/worace/.ivy2/local/com.example/lib-a_2.12/0.1.0-SNAPSHOT/ivys/ivy.xml


*** Publishing lib-b to local ~/.ivy2 ***
# ...
[info]  published ivy to /home/worace/.ivy2/local/com.example/lib-b_2.12/0.1.0-SNAPSHOT/ivys/ivy.xml


*** Running App Example Via SBT run (multi JAR) ***
[info] running com.example.App
*** Running Example App.scala ***
*** Reading pizza.txt as Resource from lib-a ***
Lib A Pizza.txt Resource
# PROBLEM: the code from lib-b sees the resource file from lib-a
*** Reading pizza.txt as Resource from lib-b ***
Lib A Pizza.txt Resource


*** Building Assembly JAR ***
---> This will fail because no merge strategy is set for pizza.txt <---
# ...
[error] 1 error was encountered during merge
[error] java.lang.RuntimeException: deduplicate: different file contents found in the following:

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published