how do you include 3rdparty lib/software with your java software? - java

i am setting up a java project now. in the past, we always included everything (unzipped) from the 3rdparty, such as ant, junit, jfreechart, and others, inside our release. I am wondering is it possible just take those related .jar files but not everything with our software release? then we can get a smaller and neat release. Those 3rdparty library licenses don't allow us to do that way? what's your way? thanks,

You really want to retain the separate jars, if possible. Check out the maven appassembler plugin. It does a nice job of putting together an "unzippable" installation for you, in a controlled way. In the result you'll have a very straightforward "repo" directory filled with all of your dependencies.

I use the maven-assembly-plugin to build a single jar for each application. The plugin quickly handles the fuss of unzipping all the library jars and putting the whole lot back together as a single jar. It also supports writing a manifest with a main class specified which makes running the application simple from a command line (much simpler than specifying a classpath argument as long as your arm anyway).

If their licenses say that you should distribute derivatives with sources, then you are obliged to do that by law.
Another question is if they really force that. As far as I remember GPL, you shall distribute the sources if you want, but there is another way - you must make sources easily availiable to users. So you can drop sources in your distributables.
Any way, you should look at the licenses.
EDIT:
If you will decide to pack the whole program into single jar, I recommend Proguard. It is java optimiser, shrinker, and much more - all in one! To pack everything into one jar, just specify all your jars - program and libraries - as program jars, and specify only one jar as output. Usually it works just fine.

Related

Deploying JARs with Java 9 and above (JDK11 in this case) (JLink confusion?)

I'm a Java veteran, but I've been using JDK8 for a long time. I've decided I finally want to upgrade, so I've been using Java11. I've been enjoying the new features, but I've gotten the point where I need to deploy my software.
In the past I would export a runnable JAR from Eclipse and bundle it with an appropriate JRE. Then I'd use both to run the software from an OS-specific program (e.g. an EXE file that fires up the bundled JRE with the given JAR). Of course, now this isn't really an option because JREs are a thing of the past. Supposedly the new system in its place is much lighter weight and straight forward, the only problem is I can't figure out how to actually use it.
I've been reading about how to deploy programs with JDK9 and above and have seen people mention JLink and link documentation to it, but I can't seem to find a straight answer on how to just simply export a runnable JAR. The thing is - I don't really need all of the module support and don't really want to have to configure it. Is there a tool for simply exporting something I can run? How is this done now?
Sorry if this is a dumb question, I'm just genuinely confused at how this all works and can't really find anything online that lays it out in a clear and concise way. There's a lot of documentation on JLink and what it does, but I haven't really found anything that explains the root purpose for all of it.
TL;DR; how do I export working Java programs with JDK9 and above using Eclipse (latest version)?
Thank you for your time!
...how to just simply export a runnable JAR.
Well, if you're not planning on using modules for your application classes, the JAR part should be the same as before. You basically just have to create your own JRE using jlink, e.g.:
jlink --add-modules java.se --output jre
That would create a jre folder with a runtime image that includes all the java.se modules.
You can then bundle that with your JAR like before.
The interesting part here is that you can pick and choose which modules go into this runtime image. java.se is an aggregator module that transitively includes a bunch of other modules. But you could also specify your own specific list of modules, leaving out some of the ones you don't need, making the final runtime image smaller.
I've spent literally months on trying to figure out how to create a single, clickable executable using Java 9+. I now conclude that it is impossible. Whether you use jlink directly yourself, or indirectly via Maven or Gradle, the result is that jlink produces a full directory structure that you are left to "distribute to your users" (somehow, I guess magically, since nothing in Java 9+ tells you anything about how you're supposed to do this). Then, once your user (somehow) has this directory on their machine, they are forced to invoke runtime-image-directory/bin/your-program-name. As though your user is a programmer who is happy to have to install a directory structure, and drill down to invoke a specific file name, which is buried in a directory with lots of other files, rather than being a user who USED to be able to simply double-click on a .jar file to run it. This makes me really wonder if whomever designed all this thought at all about the "user experience". The fact that there appears, as of Java 9+, to be NO WAY to simply deliver ONE file (such as a .jar) to users, together with the fact that just BUILDING this "runtime image" is fantastically complicated, means that developers are going to abandon Java in droves. It really seems to me that the brainiacs at Oracle simply didn't think this through. They have created a death knell to Java by making something onerous for developers to build and distribute, and onerous for users to invoke. I don't see how this situation can be allowed to remain without Java ultimately dying off. Somebody please correct me if I am missing something here, but I've spent months now trying to figure out how to create a runnable jar in Java 9+, USING MODULES, and it appears there is no way to do it.

Is there anything like "Java shared libraries" for minimizing disk footprint of deployed applications?

Let's imagine, I created a bunch of command line utilities, written in Scala and/or Java, and I'm using SBT to build them. They all use a couple of libraries, some of them pretty big, and in case of Scala, also the (not so small) Scala standard library.
I want to have these utilities in completely built form (runnable .jar files) to be able to instantly launch any of them and, if needed, also easily distribute them. But what I don't want is to include their dependencies in all of them, because they will be taking disk space. Instead I want them to get dependencies from a shared folder at runtime, and the application jar should contain only "my" classes.
The question is, is there a standard way to accomplish this? If so, where must be shared .jars located? Otherwise, what would you recommend to do?
You can set the CLASSPATH for this.
The JRE searched for classes in the .jar files named in the CLASSPATH.
Additionally all .jar files in the directory jre/lib/ext are used.
To find the complete serching in classpathes please consult the official documentation from Oracle.
Something you might like to consider (although it will require slightly changing what you plan to do) is to have a local Maven repository.
You could have SBT publish libraries to it when they're built. Instead of building runnable JARs, you could run your applications via SBT, which would pull libraries from the local repository as/when required.
The benefit of this is that all the plumbing to do this is built into SBT, and it would make distribution trivial.
The downside is that you would have to run your apps via SBT instead of building runnable JARs. Whether that will work for you, I don't know.

Deploy Jar With Java?

I was wondering how to include Java itself with a jar file so that people don't have to have Java installed already. Is it possible and if so, how do you do it?
To execute the jar in the first place you'd need to have java installed. So it would be best to include a JRE installer in a separate file if you'r including one. Also, you'd have to have a different installer for each target platform so this would be somewhat impractical for general distribution because of the inflated file size.
This is like asking "Can we include the chicken that lays the egg, in the egg?". Answer, no.
As to solving the bigger problem though, there is at least one strategy that might work well for applets, JWS apps. and (possibly) single Jars of desktop apps. that are launched from a link (I've never tried that, though). This approach uses JS to check for the right JRE before providing a link to the Jar.
In order to get a computer to do something, you need to have code that the operating system knows how to handle. Most modern operating systems do not know how to handle Java code unless you install a Java Runtime Engine - to them JAR files are just ZIP files.
Hence you need some code which can be executed directly (without Java) and the simplest is just to use a Java launcher. Many exist - see Java packaging tools - alternatives for jsmooth, launch4j, onejar - but e.g. launch4j is maintained and supports the <path> tag to specify a relative path to an included JRE. Those are unfortunately rather large, but you could provide two versions. One with the JRE, and one without (which then prompts the user to install a JRE).

Grouping Jar's Under lib

The external jar files are placed under /Library/Java/Extensions on Mac OS X, i have multiple applications that depend on a group of jars such as JavaMail Api, if i dump all the jars in the folder java picks them up, but what i want to do is group them together such as all mail api jars go to the mail folder. But if group them under folders they are not picked up by java. Do i have to just dump them in to Extensions folder? It would make my life a lot easier when updating to group them.
No, they should resize directly under /Library/Java/Extensions/.
However, you can always pass -Djava.ext.dirs=... as an additional argument when you invoke Java programs.
As a sidenote: If you're about to manage dependencies for your projects, try look into build tools, which declaratively resolve dependencies, such as ant.apache.org/ivy or maven.apache.org.
You should not use the global extensions library unless you really, really have to.
Basically your programs should be self contained units with library code on top of a stock JVM, this will allow different programs to have different requirements regardring library code versions, and it will also work when used on other machines.
Pick a good IDE (Eclipse, NetBeans, perhaps Xcode but I have not used it) and learn to add jar files to your projects. It will make you a more attractive programmer to a future employer.
I do find this behaviour annoying myself, that you have to have a flat folder structure when referencing external jars (if you don't add the jars individually).
However, if you don't mind grouping them into jar files instead of grouping them into folders, I would recommend One-Jar.
Quoting: "One-JAR uses a classloader which knows how to load classes and resources from Jar files inside a Jar file. "

Merging Multiple Jars in to a Single Jar

my application needs multiple jars to work. Since it is a desktop application i can not hold the user responsible of installing. So in my build script i unzip the jars content in to my build directory delete manifest files, compile my software and jar it again. Everything works as it should my question is are there any long term side effects to this process?
In the past, there were JARs with weird content (like the DB2 driver which contains com.ibm and com.IBM; after decompressing in a Windows filesystem, those two packages would be merged).
The only issue you need to be aware of are signed jars and other files in META-INF which might have the same name in multiple source JARs.
A simple solution for all these issues is to use One-JAR. It allows to wrap several JARs into one without unpacking them, first. And read this answer: Easiest way to merge a release into one JAR file
A simpler solution (IMO) is using Maven's assembly plugin, which is also described in one of the answers to another question which was linked to in a previous Q&A. This is provided you are using Maven (which is a recommended tool by its own right) as a build tool.
If you want a no fuss way for the end user to kick off a program with multiple jar dependencies you may want to look at Launch4j or Jsmooth (I prefer Launch4j). Both are programs that create executables that wrap jar(s) and the JRE together so that to the end user it appears no different then any other executable.
Another great option is ProGuard, which can also shrink and/or obfuscate the code too.
If your primary target platform is Windows desktop, then you could also consider generating an Windows native exe from the jars of your application
If some of the jars are signed you lose the signature by unpacking/repacking it.
Well you're throwing away the MANIFEST of your third party jars, so that could cause you problems. For example you could be causing security issues by throwing away the "Sealed" attribute.
Why not just create a simple installer and a script to launch your application which sets the CLASSPATH correctly?
One-JAR will do the job, and has a new release (0.97) which supports frameworks like Spring and Guice, which users are now packing into One-JAR archives. http://one-jar.sourceforge.net
Ference Hechler also did some great work inside Eclipse with the Eclipse export wizard: we worked together on FatJar/One-JAR from which the Eclipse work grew, and I can recommend that as an approach, though I don't know how well it handles the frameworks.

Categories