The app consists of modules and each module is particular maven project with one parent. These modules are used as jars in main app.
Each module uses third party SDK via maven.
These SDKs have many dependencies and these dependencies can be with the same group and artifact but with different versions. It is hard to manage them and we have problems with 'NoSuchMethodError's. As for me the simplest way to fix problem is to get sources of problematic dependencies and source of SDK, change the package (add some prefix) and imports and put it inside sdk jar.
But this approach requires: one more git repository for forked SDK's jars and private maven repository to publish them and a lot of time.
Is there maven plugin that can help with this problem, for example plugin that can build jar (our module jar) with all dependencies included inside it but can change package of all dependencies?
You can try to use the Maven shade plugin which allows you to relocate classes
https://maven.apache.org/plugins/maven-shade-plugin/examples/class-relocation.html
but I have never tried this myself.
In most cases it is better to try to align the dependencies so that you use the same versions in most places and also to reduce dependencies to a minimum.
Congratulations, you are confronted with a classpath problem called "jar hell". The only safely working solution i know is the use of different classloaders for each version of the same class (if it's not backward compatible).
A class is identified by its qualified name (package and class name) and by the classloader it has been loaded. If the application uses the default system classloader and there is the same class in different versions in the classpath only one version will be loaded by the classloader. In the oracle JDK/JRE it is the one which occurred first in the classpath. If you are lucky you can bring the classpath (order and excluding dependencies) in a special order in which your application will run, but i wouldn't recommend it since it relies heavy on the JDK/JRE implementation.
OSGI is a technology which might be helpful for this since it provides a module based framework for using different classloaders.
Related
When developing Java libraries we're currently using the Apache Maven Shade Plugin to hide internal dependencies on other libraries (jars) by renaming their package names.
Is it possible to hide these internal library-dependencies by using the Java 9 module system and not exporting the name of the internally used libraries?
I.e:
Both module A and B include, but does not export, class org.codehaus.jackson.map.ObjectMapper (included using e.g. Maven Shade plugin) with different versions for the class
Module A uses module B
Will each module still use its implementation org.codehaus.jackson.map.ObjectMapper?
I believe it should by so, but I have found no documentation explicitely confirming this, nor any texts / examples recommending this approach for this quite usual versioning issue.
This issue is described as http://openjdk.java.net/projects/jigsaw/spec/issues/#MultiModuleExecutableJARs and there's no support for it yet. In case all dependencies are modules, it would make sense to use jlink to solve this. But as long as there is at least one non-module, there's no solution available yet. This is something that needs to be solved within the JDK/JRE.
It is still a valid case, so I would suggest to ask this question the at jigsaw-dev mailinglist and refer to #MultiModuleExecutableJARs
From Jigsaw Project:
Make it easier for developers to construct and maintain libraries and
large applications, for both the Java SE and EE Platforms.
I'm trying to learn what project Jigsaw is and till now it seems that the goal of Project Jigsaw somewhat overlaps with what we did using Maven (or Gradle) dependency management:
Is it a threat to build tools like Maven?
Or my understanding is wrong and project Jigsaw is going to complement these build tools in some way?
Very simplified answer
After Jigsaw, public will be public only within the JAR scope. To see the class outside the JAR it must be exported.
Java will force modularization because any inter module interaction will have to be specified in the module-info file.
For example, if you produce a WAR it will remain almost unchanged but all JARs packages in the WAR must define a module-info (or not define it and be treated as automatic or unnamed modules).
Maven has 2 main features: dependency management and building:
Dependency management means Maven can determine versions of libraries
and download them from repositiories.
Building means Maven can compile code and package it into artifacts.
To conclude: Maven will still be responsible for building, but one must learn how to compile and package using Jigsaw modules.
Modules are not in any way a threat to build tools. Modules complement build tools because build tools construct a dependency graph of artifacts and their versions at build time while modules enforce dependencies of artifacts/modules (not including versions) at build time and run time.
From the State of the Module System:
"A module’s declaration does not include a version string, nor
constraints upon the version strings of the modules upon which it
depends. This is intentional: It is not a goal of the module system
to solve the version-selection problem, which is best left to build
tools and container applications."
I have a project that has some dependencies. Some of those dependencies are Mavenized and some of them aren't.
Two dependencies use the same class, but from different packages, one from Java Libs and the other one from GWT libs. This makes the app crash.
MyPackage Depends On: Package A
MyPacakge Depends On: Package B
Package B and Package A are conflicting.
Currently the only solution I've found was to exclude one the conflicted dependencies.
Is there any plugin for Eclipse-Maven or any workaround to easily solve this?.
Thanks.
In my opinion,2 or more classes with the same package path and same class name mixed in the class path,the first class loaded will come into use,and the later ones are all ignored.And no exception or even currution will happen.
This jvm class loading rule is frequently used in enterprise app to fix bugs quickly.Make a jar named with name of 'a_name_yyyyMMddHHmmss.jar' to replace the mis-coded java class with out compiling the whole projects and upgrading.
Would you please add your exception log or something?
I have several advise:
Make sure the GWT version and jdk version the 'same'/compatible.
Use the "Dependency Exclusions" of maven pom config.Refer here.
I am writing an application plugin in Java, and my plugin has dependencies on several third-party JARs. I am bundling these dependencies with my plugin so that I can deploy just a single JAR file.
The host application may also be running plugins from other vendors. Unfortunately the host application puts all the plugins on the classpath, and I am not able to change this behavior. If another vendor's plugin is loaded before mine and uses an incompatible version of a dependency, my plugin could crash.
I am not able to test compatibility between my plugin and other plugins ahead of time. It is also not acceptable for me to say that there is an incompatibility between the plugins--if my plugin crashes, it reflects poorly on my company. The customer does not care why my plugin crashes, they will attribute it to poor programming on my end.
I am looking for a way to prevent other vendors' plugins from interfering with my own. Is it possible?
I've heard of custom classloaders but I'm not sure if that solution will work for me.
You can use Uberjar. What it does is move all your jars/classes to a custom namespace so that none of your classes clash because your dependencies have a different namespace.
You might want to look at maven-shade
You could try to embed an OSGi container in your plugin. This would allow you to run and load dependencies as OSGi bundles in isolation from the system classloader.
Instructions for Felix.
I'm trying to build an Eclipse plugin that depends on a library which has to be distributed separate to it. The reasons for that are:
It's a commercial library, while the plugin will be distributed freely. Also, most people won't need it and we don't want to confuse users.
There are currently at least two versions of the library in use and we don't want to build two different versions of the plugin. The interface is compatible, so we can ship just one version of the plugin.
The plugin is for an Eclipse-based development environment and the purpose is to provide our library's functionality within that environment. The library itself depends on other free components, which I can bundle with it without a problem.
Since I don't know if I'm allowed to say exactly which library it is, but I must keep this unambiguous, let's call the library "L" and the plugin I'm trying to develop "P".
I'm using the bnd tool for this and so far I've tried both packaging L as a standalone plugin, and as a plugin fragment.
As a standalone plugin, it was accepted by the host eclipse environment and I could list it as a dependency of P and successfully build that. However, at runtime the P plugin didn't see resources from the L library on its classpath. Mainly those in META-INF/services are needed.
Next, I tried packaging L as a plugin fragment for P. I hoped this would work, since the specs say, that a fragment's classpath is merged with its host plugin's. This didn't work, because I couldn't use the classes from L as build dependencies of P - putting L in eclipse's plugins directory didn't result in it being recognised as an installed plugin.
So I'm stuck. I need L's jars as part of P's runtime and build classpath, while at the same time having them in a separate plugin. Is what I'm trying to do even possible?
For P to have visibility of L's resources, L must export the containing folders as 'packages' and P must import them. This looks a bit inelegant but does allow folders like META-INF/services to be on P's classpath.
Alternatively, for META-INF/services in particular, you could look at new function in release 5 of the Enterprise OSGi spec in the area of ServiceLoaders. A good blog explaining the idea is http://coderthoughts.blogspot.co.uk/2011/08/javautilserviceloader-in-osgi.html, and Apache Aries has an early implementation.
Eclipse plug-in dependencies on other plugins can be defined as Optional. If the user does not have it you can use Class.forName to check if the dependent class has been loaded.
Apparently you didn't list the 'library' plugin as an OSGI import of the 'main' plugin. Without seeing your manifests it's impossible to tell for sure.
As per my understanding,You want to add Jar as plugin dependency.
The best way to do so Go to Plugin View--> Copy your jar file to plugin directory -->Import it as a source project in your workspace.
Plugin.xml-->dependency tab-->add it as a dependency.
If you want to package it in the plugin,use dynamic library loading mechanism.