Is it right or wrong for a Java JAR to contain its own dependencies?

I think this is a two-part question. I am trying to write my own Ant task ( MyFirstTask ), which can be used in other build.xml buildfiles projects. To do this, I need to compile and package my Ant task inside my JAR. Since this Ant task that I wrote is quite complicated, it has about 20 dependencies (other JAR files), such as using XStream for OX mapping, Guice for DI, etc.

I am currently writing the package task in the build.xml file inside the MyFirstTask project (the assembly file that will pack myfirsttask.jar , which is the Ant reusable task).

I suddenly realize that I do not fully understand the intent of the Java JAR. Is it that the JAR should not contain dependencies and leave it to run-time configuration (application container, runtime, etc.) to provide it with the necessary dependencies? I would suggest that if so, the executable JAR is an exception to the rule, right?

Or, is the Java JAR intent to also include their dependencies?

In any case, I do not want my users to copy-n-paste 25+ JARs into their Ant libs; it's just cruel. I like the way WAR files are configured, where the class path for the dependencies is defined in the classes/ directory.

I assume that in the end I would like my JAR structure to look like this:

 myfirsttask.jar/ com/ --> the root package of my compiled binaries config/ --> config files, XML, XSD, etc. classes/ --> all dependencies, guice-3.0.jar, xstream-1.4.3.jar, etc. META-INF/ MANIFEST.MF 

I assume that to accomplish this (and get the path to the runtime class so that it also classes/ directory), I need to somehow change MANIFEST.MF (I know there is a manifest attribute called ClassPath , I believe?). It's just hard for me to put everything together, and I have a looming / protracted question about the very intention of JARs to start with.

Can someone please confirm if Oracle wants the JARs to contain their dependencies or not? And anyway, what would I have to do in the manifest (or somewhere else) to make sure that the class path can find the dependencies stored in the classes/ directory during execution? Thanks in advance!

+4
source share
5 answers

The term "JAR file" can mean at least two things, or rather, has at least two facets of their meaning. This basically means the container format: basically, a ZIP file with the META-INF directory. In more detail, this means that this container is used as a way to batch class files.

In the sense of having a container, there is no intent regarding the contents; the file may contain class files, other JARs (in any sense!), etc. But in the sense that I am a package of code, I believe that the goal for JAR files is not to contain any dependencies.

If you read the JAR File Specification , you will find that there are several allusions to storing class files, but nothing about storing other JAR files. Accordingly, if you look at the implementation of the JAR file class loader in the JRE, it will not be able to do anything useful in nested JAR files.

In addition, the JAR specification describes in detail how to work with non-nested dependencies: the Class-Path attribute . This allows the JAR file to link to other JAR files in the file system.

Now in JAR files in JA format, files are not the only use of JAR files in-sense-of-a-container. WAR, EAR and RAR (and much more) are all JAR files used for specific purposes. Each of them can contain other JARs: WARs can contain JAR files in JS-format, and EARs can contain those as well as WAR. However, these are completely different animals than JAR files in their class. It is worth noting that their use requires special class loaders that are not part of the standard Java library.

The way WARs, etc. can collect many JAR files together, it is really very useful, and this is a real shame that does not have a common mechanism for doing this in Java outside of Java EE. It would be great to have an “application archive” or “meta archive” that simply bundled some JARs.

So, you still have the problem of users who need 25 JARs to use your plugin. You have about two options.

First, you accept the pain and distribute your plugin as a ZIP full of JARs that users will need to unzip.

Secondly, you join the 21st century and use a build tool and distribution mechanism that automatically handles dependencies: in practice, this means using Gradle or Maven or some other tool (like Ant) with Ivy to get dependencies on Maven Central, and then release your code along with the POM file that lists these dependencies. Users can then load your JAR and your POM and have their own build tool to get the dependencies.

If you are on the second route, it might be wise to also release zip dependencies, in the interests of users who do not use automatic dependency management.

+3
source

The goal (AFAIU) is that JAR files behave like common code files ( .so on Unix, .dll on Windows). Typically, an application will install several shared object files in the form of siblings, as well as an executable file from which to run them.

An executable JAR is more like a standalone executable file, so the inclusion of all dependencies is more common (similar to how an executable with a static connection contains all its dependent objects).

Unfortunately, by default, ClassLoader cannot load classes from nested JARs. You can write a Loader class that does. Or you can use someone else. From the description of your problem, it sounds like Jar Jar Links - exactly what you are looking for.

+3
source

Is it right or wrong for a Java JAR to contain its own dependencies?

There are times when the JAR file correctly contains its own dependencies. If you want to support users who do not use modern dependency management, you can provide a JAR file containing your Ant task code, as well as all dependencies. A more powerful, flexible and modular approach is to publish JAR file versions to the Maven repository , which contains only project code.

1) JAR file containing the project code and all the dependencies

Pros

Ant target example for creating a JAR

 <target name="jar" depends="compile" description="Creates a standalone JAR of all class files and dependencies."> <jar destfile="${my.ant.task.jar.file}" update="true"> <fileset dir="${build.classes.dir}" /> <zipfileset src="${lib.dir}/javax.inject.jar" /> <zipfileset src="${lib.dir}/guice-3.0.jar" /> <zipfileset src="${lib.dir}/guice-multibindings-3.0.jar" /> <zipfileset src="${lib.dir}/guice-assistedinject-3.0.jar" /> </jar> </target> 

Vs

  • If the end users of your Ant task already have some or all of the dependencies included in their projects, then they will get redundant copies of the Dependency
  • JAR file can be very large

2) A JAR file containing only your project code published in the Maven Repository

Pros

  • Users can get any version of your Ant task that you published to the Maven repository , which provides more flexibility when releasing new versions of your task, allowing existing users to continue to use previous versions to avoid possible regressions.
  • Prevents duplication of copies of common dependencies (unless different versions of the dependent causes cause errors)
  • The JAR file will be small.

Vs

You need to find out the following:


For reference: Java & trade; The tutorials provide a good summary of the JAR files.

Lesson: Packing Programs in JAR Files

Java & trade; Archive (JAR) file format allows you to combine multiple files into one archive file. Typically, a JAR file contains class files and auxiliary resources related to ... applications .

The JAR file format offers many advantages:

  • Security: you can sign the contents of the JAR file digitally ...
  • Reduced loading time: if your applet is associated with a JAR ...
  • Compression: JAR format allows you to compress your files for efficient storage.
  • Packaging for extensions. The extension framework provides that you can add functionality to the main Java platform, and the JAR file format defines the packaging for the extensions ...
  • Package Seal: packages stored in JAR files can be sealed so that the package can ensure version consistency. Packing a package within a JAR file means that all classes defined in this package must be found in the same JAR file.
  • Package Versions: A JAR file can store data about the files it contains, such as vendor and version information.
  • Portability: The JAR file processing engine is a standard part of the Java platform kernel API.
+3
source

Jar Jar Links is for standalone applications only. But not for Ant. If your project has the same dependencies, and later they will be updated to later versions, for example xstream - *. Jar, then a conflict will arise, and the wrong version may be chosen. In the worst case, there will be a MethodNotFoundException. That's why bad practice is to include dependencies in one jar.

What is the problem with "I don't want my users to copy-n-paste 25+ JARs"?

This is the simplest solution. And the best, because you will avoid problems in the future.

Now that you see the inconvenience of Ant, you can compare it to Gradle. With Gradle, you get tasks a bit like Ant, and you don't need to provide any jars with dependencies. All dependencies will resolve Gradle for you. And as in Ant, you can still create your own tasks.

+1
source

Some Java application providers use the following script to distribute their application, which depends on other banks, it resembles static binding . At the stage of constructing the jar, all dependencies (being also jars) are unpacked. When creating the final jar, they include both their newly compiled classes and classes extracted from the dependencies.

Possible problems:

  • Applications cannot reuse libraries because they are contained in the application. The usual static communication problem.
  • Repackaged library licenses must be respected. Usually this will normally repack them, but sometimes you need to pay extra attention to your license files, which may be in their banks.

AFAIK cannot have banks in the bank, or it will be impossible to indicate the path to the classes for them. Consequently, the repackaging procedure.

0
source

Source: https://habr.com/ru/post/1437043/


All Articles