This week's book giveaways are in the Jython/Python and Object-Oriented programming forums.
We're giving away four copies each of Machine Learning for Business: Using Amazon SageMaker and Jupyter and Object Design Style Guide and have the authors on-line!
See this thread and this one for details.
Win a copy of Machine Learning for Business: Using Amazon SageMaker and JupyterE this week in the Jython/Python forum
or Object Design Style Guide in the Object-Oriented programming forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
  • Knute Snortum
Sheriffs:
  • Liutauras Vilda
  • Tim Cooke
  • Junilu Lacar
Saloon Keepers:
  • Ron McLeod
  • Stephan van Hulst
  • Tim Moores
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Joe Ess
  • salvin francis
  • fred rosenberger

Runnable jar can't find library

 
Ranch Hand
Posts: 424
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, I am having trouble with a runnable jar not finding an external library. The library is Jackson. It's in my pom file so it compiles. But when I go to run the jar it gives me a "cannot be found" error. How do I make the library visible to the jar?
 
Saloon Keeper
Posts: 11188
244
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You have to add the library to the classpath or modulepath when you run your application. How you do this depends on how you're running your application.

For an executable JAR, you need to add a reference to the library to the JAR's manifest. You can easily do this by configuring the maven-jar-plugin in your POM. It should look roughly like this:
 
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Actually, if I read Stephan's sample properly, it's not recommended practice. A good Maven POM should not be reaching outside of the project directory for resources, and in fact, Maven is constructed to make doing so quite difficult. If you cannot simply do a "mvn clean", zip it up, email it to Wakanda and have someone there be able to instantly build everything. it's a poor project. Real Life is, of course more complex than that, but it's still the essence of the concept.

In cases where a library JAR is not in the public Maven archives, the recommended process is to catalog it into your local Maven archive. Or, if your site has a shared archive/proxy such as Nexus, catalog it there. I've had to do this on occasion.

However, Jackson is very definitely part of the stock archives. To include it into a JAR build all that should be required is to correctly define its scope. It should be "compile", which is the default. If you instead made it something like "provided", then Maven would include Jackson in the compile classpath but not in the constructed JAR, as it would expect that whatever app used that JAR would provide it. That's common when using JEE APIs in webapps, as an example.
 
Stephan van Hulst
Saloon Keeper
Posts: 11188
244
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The snippet I posted will take the projects runtime dependencies and list them as Class-Path entries in the JAR's manifest. It doesn't require anything that's not already there during compilation time. All it does is allow the JVM to look for the executable JAR's dependencies in a location relative to the JAR. I don't think it's very strange for an installed application to have the executable JAR in a main folder and its dependencies in a separate lib/ folder.
 
M Burke
Ranch Hand
Posts: 424
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is is possible to include the library in the compiled jar? It would be good if this thing will run stand alone.
 
Tim Holloway
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

M Burke wrote:Is is possible to include the library in the compiled jar? It would be good if this thing will run stand alone.



Yes, there's a Maven plugin to create executable JARs. And, as I said, if your library is defined by a dependency whose scope is "compile" it will be included automatically.
 
Tim Holloway
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote: I don't think it's very strange for an installed application to have the executable JAR in a main folder and its dependencies in a separate lib/ folder.



Sorry, but that's not the Maven Way. Maven expects libraries to be managed and supplied by the dependency system. If you have a library JAR, it should have something that builds that jar and it should have a version number, since Maven is very big on reproducibility over a software product's lifecycle. If possible then, the library JARs should all have their own projects and POMs and they should install themselves to a Maven repository. For projects which cannot be built that way (I had issues, for example with IBM's DB2 JDBC jar), you should take that JAR and publish it to the Maven repo with a version number - their own, if one's available, or one you assign yourself if not. That future-proofs your project because you have the ability to use multiple versions of the JAR in question when the inevitable fixes and upgrades come in.

Trust me, I tried very hard to do it the way you suggest and the results were not much fun. Maven can be rather autocratic and I'm the rebellious type. In particular I didn't like their standard directory structure. But I've learned that it's a lot less work overall if you work with it and not against it.
 
Stephan van Hulst
Saloon Keeper
Posts: 11188
244
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Then how do you run the applications Tim? Do you expect all your clients to have Maven installed?

To be clear, I agree with you to do everything the Maven way up until deployment. After the product is deployed, Maven's job is done and things are done the Java way. And Java's way of referencing runtime dependencies from executable JARs is through the manifest file.
 
Tim Holloway
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That assertion makes no sense. Take a look at how Maven builds a WAR. A WAR is a JAR with two internal classpaths. One is /WEB-INF/classes, where loose classes and other classpath resources go. One is /WEB-INF/lib where copies of library JARs - as defined by the POM dependencies - go.

In the case of a WAR, the webapp server adds - as part of the deployment process - the /WEB-INF/classes to the classpath of the webapp context. Then it enumerates each of the jar files in /WEB-INF/lib and adds each JAR in /WEB-INF/lib to the webapp context classpath.

An executable JAR operates similarly, except that in that particular case, the Maven Executable Jar mojo injects logic internal to the executable JAR to add the libraries to its classpath. Because regardless, Java never looks inside of JARs within a JAR for classes on its own. That's a fundamental characteristic of Java.

That's why you don't need - and should not have - a /src/main/resource/lib directory full of libraries. Maven pulls those libraries straight from the repository when it does the build, copies them into the artefact it's constructing, and adds the magic that makes them part of the executable internal classpath. Thus Maven need not be anywhere near the application user. Once properly built, the JAR is, in fact, independent of its builder.

And, conventienly, the project itself is smaller, since it doesn't carry the freight of manually-inserted (and possibly outdated) clones of the libraries.
 
Stephan van Hulst
Saloon Keeper
Posts: 11188
244
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The project page for the Apache Maven JAR Plugin outlines exactly how to make an executable JAR, and it's as I've demonstrated here, so you can't tell me it's not "The Maven way" when it clearly is. I also never mentioned that you need a src/main/resource/lib/ directory full of dependencies. I'm not getting where you're getting any of that stuff.

The Maven JAR plugin also does not build in any logic or dependencies into the JAR. It uses Java's regular manifest mechanism. What Mojo are you referring to? The maven-shade-plugin? You'd use that to build a fat JAR, but not everybody is into fat JARs and there's also nothing to indicate that skinny JARs are 'not Maven'.
 
Tim Holloway
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

M Burke wrote:Is is possible to include the library in the compiled jar? It would be good if this thing will run stand alone.



In other words, a "fat jar" was exactly what was desired. Other architectures are moot.

Maven is not obligated to deal with jars external to the JAR it's producing. If you choose to include a classpath manifest in a Maven-produced JAR, that's fine. Just don't expect the POM to magically make those external JARs available. Maven just copies the manifest, it doesn't attempt to resolve it.
 
Stephan van Hulst
Saloon Keeper
Posts: 11188
244
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's all fine. I just responded to your first message in this topic. I still don't see how a skinny JAR is against recommended practice.
 
Tim Holloway
Saloon Keeper
Posts: 21603
147
Android Eclipse IDE Tomcat Server Redhat Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:That's all fine. I just responded to your first message in this topic. I still don't see how a skinny JAR is against recommended practice.



It's not. Maven doesn't care. However, the reason one would generally prefer that an executable JAR be fat is because way you only have to deploy one JAR instead of half a dozen or more. Or course, if you had multiple executable JARs all living in the same directory and sharing the same libraries, you'd see an advantage to skinny JARs. Or at least you used to. These days, disk is so cheap and logistics are so expensive, even then a lot of people would go with fat jars just to reduce the cost of field support.
 
M Burke
Ranch Hand
Posts: 424
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, I got it working. I added a plugin to the pom. When I look at the compiled jar there are no entries in the manifest. I downloaded the Jackson libs and added then to the class path earlier.

I am not sure why this worked.

 
Stephan van Hulst
Saloon Keeper
Posts: 11188
244
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The assembly plugin likely wraps your main class with a main class of its own, in which it first loads the contained libraries and then calls your actual main class. The manifest is only used to reference class files and JARs the normal way (when they're not packaged inside your fat JAR).
 
There will be plenty of time to discuss your objections when and if you return. The cargo is this tiny ad:
Sauce Labs - World's Largest Continuous Testing Cloud for Websites and Mobile Apps
https://coderanch.com/t/722574/Sauce-Labs-World-Largest-Continuous
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!