Does Java 9 modules can help with solving dependency conflict? I have included two dependencies, protobuf-java and protobuf-lite, they both contains the same classes under the same packages (FQN), the problem is implementations differs a bit from each other. Both dependencies comes from two different jars and i need both in single module. The problem is, that class loader takes just the first one on the classpath which leads to unexpected behavior like NoSuchMethodError or NoClassDefFoundError.
Do you have any idea how can I solve this problem? I guess i have to force loading these dependencies by different class loaders, right? Could you provide some examples which shows how to deal with it?
Related
My experience with Java class loading is limited. With tools like Maven I have a rusty understanding of how they resolve dependency versions. But I've hit a problem that's making me question how Java loads classes.
My scenario, I have a dependency on version 30.1.1-jre of com.google.guava. I also have a shaded jar which has a dependency on Guava 18.0.
In my application I end up seeing the following exception
java.lang.IncompatibleClassChangeError: Class com.google.common.base.Suppliers$MemoizingSupplier does not implement the requested interface java.util.function.Supplier
which I cannot reproduce locally. Based on https://github.com/crabhi/celery-java/issues/9 it sounds like this error is produced when an older version of Guava is on the classpath.
Checking the classes in the war I see
WEB-INF/lib/java-driver-shaded-guava-25.1-jre-graal-sub-1.jar.d/com/datastax/oss/driver/shaded/guava/common/base/Suppliers$MemoizingSupplier.class
WEB-INF/lib/nautilus-es2-library-2.3.4.jar.d/com/google/common/base/Suppliers$MemoizingSupplier.class
WEB-INF/lib/guava-30.1.1-jre.jar.d/com/google/common/base/Suppliers$MemoizingSupplier.class
This makes me think the shaded jars are causing a problem.
Is that possible? Are there any articles explaining how classes are loaded when shaded jars enter the picture?
You have two copies of com.google.common.base.Suppliers.MemoizingSupplier on the classpath. Only one can be loaded, and in your case, it's the older version.
You shouldn't have multiple classes with the same name available to one classloader. What is nautilus-es2-library-2.3.4.jar and why does it bundle Guava rather than expressing it as a transitive dependency?
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
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'm using jarX that has embedded dependencies that conflict with my own dependencies, so I'm creating a classloader to isolate jarX's dependencies from my main classloader.
jarX is outside my app's classpath, but my classes that use jarX's classes are in my classpath, so when I instantiate my classes loaded via the custom classloader, I run into the class identity crisis in the form of ClassCastException as the JVM's version of my classes are considered different from those loaded by my custom classloader.
I found this blog post where they solved a similar problem by only interacting with the custom classloader loaded classes via reflection, which seems to solve this problem.
It just feels like it should be easier than this. Does anyone know a better way to handle this problem?
The easiest way is to open jarX, remove the offending classes, and done. It is a bad practice to embed dependencies in a JAR unless that is JAR is meant to be used only as a standalone runnable fat-jar. JARs that are meant to be used as libraries should not embed dependencies.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
Can you post which jar is it and what are the classes that it overlaps, with the full stacktrace? Have a look at this tool I wrote to generate a list of duplicate classes in the WAR, there is an option to exclude duplicates of the same size.
These are some measures that can be done to solve this:
Try to reduce the number of duplicates by doing a case by case analysis of why the overlap exists. Add maven exclusions for jars that are complete duplicates.
Check if there is a version of the same jar without the dependencies that you could use, which jar is it, xerces, etc?
If there is no jar without dependencies, you can you exclude the other jar that overlaps jarX and see if the application still works. This means all components that need the jar have a compatible version of the jarX library
Separate the application into two WARs each with the version of the library you need. This will reduce the number of libraries in which
These where measures that are likelly to be more maintainable long-term
If the previous measures do not work:
open the jar, delete the duplicate classes and publish in the maven repository with a different name jarX-patched
you can configure nexus to serve a patched jar instead of an unpatched jar transparently
If your container supports OSGI that would be even better, but if you don't use a OSGI container for development as well, then the application would not work in development.
I use maven to manage a core package and two appliaction packages that both depends on the core package. For technical reasons, I can't make a full assembly for each application package, which means that I've to distribute each application package with the core package as a separate JAR which will be put in the classpath of the application.
I also need to obfuctate my JARs. I can achieve this easily for a single assembly, however, I'm not sure if it is possible to obfuscate all classes while keeping my JAR separated ?
Someone has already been faced to this problem, and if so, is there any possibility to do this with maven and proguard ?
Thanks in advance!
Although I not sure if you could obfuscate two jars separately which depend on each other, but I have seen similar things done.
This can be achievedi by keeping some clean interface(s) between the two jars. This will allow you to keep the interface between the jars as unobfuscated and rest of the classes can be safely obfuscated without breaking the dependency.
This was done on one of the product I have worked on which exposed public APIs to clients to code to but the implementation classes were obfuscated.
This solution could be painful to implement practically and will depend on degree of inter dependency between your two jars.