Imagine I'm developing module A with two dependencies for B and C. What if B depends on module D version 2.0 but C depends on D version 3.0. To make things worse let D-3.0 is not back compatible with D-2.0 (interfaces were changed for example) and B is not supported already and there is no new version of B which could work with new version of D.
Is there any way I could run A with B and C dependencies?
Is there any way to have some class different versions to be correctly loaded and used from classpath?
Thanks for ideas.
OSGi is the way. : ) I am still learning this, but the least it does it solves this problem known as Jar Hell. See here http://www.osgi.org/About/WhyOSGi
Versioning - OSGi technology solves JAR hell. JAR hell is the problem that library A works with library B;version=2, but library C can only work with B;version=3. In standard Java, you're out of luck. In the OSGi environment, all bundles are carefully versioned and only bundles that can collaborate are wired together in the same class space. This allows both bundle A and C to function with their own library. Though it is not advised to design systems with this versioning issue, it can be a life saver in some cases.
You might find this repackaging tool useful. http://code.google.com/p/jarjar/ This allows you to rename a package. (Assuming the incompatible libraries have the same packages) Once you have renamed one or both you can use the different name to distigush which package/library you want to use.
I have seen this used to create a library which five different version of xerces, selectable by package. :P
NOTE: The JRE places embedded packages under com.sun.* with packages like com.sun.org.apache.*
Whether this can be resolved is very dependent on the type of dependencies you have. If they are direct compile time dependencies, then you have a big problem and may have to do some redesign.
OSGi may help, but only if the dependencies are runtime and accessed via interfaces as OSGi services. In this way, each service used is created using its own defined dependencies (and versions) and only exposed to the user via the interface. The consumer will only have a dependency to that interface. Thus in your case, if you have only references to classes in B and C that do not have direct references to D, you should be able to utilize OSGi.
On the other hand, if you reference classes from both B and C that have direct references to classes from D, this will not solve your problem since your module will be forced to import packages with appropriate versions and your conflict will still exist.
Related
In clean architecture the structure is like that:
CORE:
CoreClass.java
SomeDAOInterface.java
IO
SomeDAOInterfaceImpl.java (implement SomeDAOInterface)
If I was supposed to split Core and IO in different .jar files, different projects, how am I supposed to handle "SomeDAOInterface" dependency in IO part? It is only contained in Core part, so I cannot really implement it without compiler error (no class SomeDAOInterface found).
What you describe is far from an unusual design, and there are plenty of examples around. For example Java EE declares a number of interfaces which are to be implemented by various containers. Or Jdbc also declares interfaces which will be implemented by database engines.
There are 2 possible designs depending on whether the binding will occur at build time or at run time.
When binding occurs at build time (common for jdbc for example), you must have an implementation available at build time, for example you declare a MySQL database driver in your project. In your example, it means the the IO project will depend on the Core one.
When binding occurs at run time (Java EE for example), you use a dummy project that only contains the interface classes (SomeDAOInterface in your example) and not the implementations for compilation and declare to the builder not to link it in the final jar but that it will be provided at run time. And at run-time you do provide in classpath a full implementation, containing both the interface classes (SomeDAOInterface) and the implementation ones (SomeDAOInterfaceImpl in your example). You will just have to read your build system documentation to know how to declare that.
Alternately, you can link the dummy project in the core jar, and declare that it will be provided in the implementation one.
If u r talking about Clean Architecture from Uncle Bob then I wonder what the CORE project is?
In case u refer to the "entities circle" then having the interface defined there is fine IF this is really part of ur core business rules.
u would then create a dependency from ur IO project (which is in frameworks or interface adapters layer) to the CORE project which is correct according to the dependency rule.
For a more detailed discussion on project structures in Clean Architecture pls refer to my post: https://plainionist.github.io/Implementing-Clean-Architecture-Scream/
I expected it's possible to use i.e. Guava-19 in myModuleA and guava-20 in myModuleB, since jigsaw modules have their own classpath.
Let's say myModuleA uses Iterators.emptyIterator(); - which is removed in guava-20 and myModuleB uses the new static method FluentIterable.of(); - which wasn't available in guava-19. Unfortunately, my test is negative. At compile-time, it looks fine. In contrast to runtime the result is a NoSuchMethodError. Means that, the class which was the first on the classloader decides which one fails.
The encapsulation with the underlying coupling? I found a reason for myself. It couldn't be supported because of transitive dependencies would have the same problem as before. If a guava class which has version conflicts occurred in the signature in ModuleA and ModuleB depends on it. Which class should be used?
But why all over the internet we can read "jigsaw - the module system stops the classpath hell"? We have now multiple smaller "similar-to-classpaths" with the same problems. It's more an uncertainty than a question.
Version Conflicts
First a correction: You say that modules have their own class path, which is not correct. The application's class path remains as it is. Parallel to it the module path was introduced but it essentially works in the same way. Particularly, all application classes are loaded by the same class loader (by default at least).
That there is only a single class loader for all application classes also explains why there can't be two versions of the same class: The entire class loading infrastructure is built on the assumption that a fully qualified class name suffices to identify a class with a class loader.
This also opens the path to the solution for multiple versions. Like before you can achieve that by using different class loaders. The module system native way to do that would be to create additional layers (each layer has its own loader).
Module Hell?
So does the module system replace class path hell with module hell? Well, multiple versions of the same library are still not possible without creating new class loaders, so this fundamental problem remains.
On the other hand, now you at least get an error at compile or launch due to split packages. This prevents the program from subtly misbehaving, which is not that bad, either.
Theoretically it is possible to use different versions of the same library within your application. The concept that enables this: layering!
When you study Jigsaw under the hood you find a whole section dedicated to this topic.
The idea is basically that you can further group modules using these layers. Layers are constructed at runtime; and they have their own classloader. Meaning: it should be absolutely possible to use modules in different versions within one application - they just need to go into different layers. And as shown - this kind of "multiple version support" is actively discussed by the people working on java/jigsaw. It is not an obscure feature - it is meant to support different module versions under one hood.
The only disclaimer at this point: unfortunately there are no "complete" source code examples out there (of which I know), thus I can only link to that Oracle presentation.
In other words: there is some sort of solution to this versioning problem on the horizon - but it will take more time until to make experiences in real world code with this new idea. And to be precise: you can have different layers that are isolated by different class loaders. There is no support that would allow you that "the same object" uses modV1 and modV2 at the same time. You can only have two objects, one using modV1 and the other modV2.
( German readers might want to have a look here - that publication contain another introduction to the topic of layers ).
Java 9 doesn't solve such problems. In a nutshell what was done in java 9 is to extend classic access modifiers (public, protected, package-private, private) to the jar levels.
Prior to java 9, if a module A depends on module B, then all public classes from B will be visible for A.
With Java 9, visibility could be configured, so it could be limited only to a subset of classes, each module could define which packages exports and which packages requires.
Most of those checks are done by the compiler.
From a run time perspective(classloader architecture), there is no big change, all application modules are loaded by the same classloader, so it's not possible to have the same class with different versions in the same jvm unless you use a modular framework like OSGI or manipulate classloaders by yourself.
As others have hinted, JPMS layers can help with that. You can use them just manually, but Layrry might be helpful to you, which is a fluent API and configuration-based launcher for running layered applications. It allows you to define the layer structure by means of configuration and it will fire up the layer graph for you. It also supports the dynamic addition/removal of layers at runtime.
Disclaimer: I'm the initial creator of Layrry
I'm facing the following problem: I have one module in my webapp that needs jaxb 1.x and the other module needs jaxb 2.x. The first module doesn't work with the new version of jaxb, and the opposite. How can I use these two jars in one project?
Thanks.
For a regular application, usually very different versions use different package names. If this is the case, you can use them both at once without problem. However if they are the same, you can use jarjar to rename the package.
However since you are using a web container each application should use the version you deploy and not the other version. i.e. the web container works it out for you.
OSGi is another container which manages the versions much more explicitly and give you more control over these issues (however I believe you need it just for this)
You have got a jar-hell issue. Generally speaking in normal java environment it's impossible to solve this problem. You have to force modularization into your project by using OSGI. Starting point: http://www.osgi.org/About/HowOSGi
If you are using the JAXB reference implementation, then you can use your JAXB 1 models with the JAXB 2 runtime by including the jaxb1-impl.jar.
http://jaxb.java.net/faq/index.html#running1Apps
As Shaman said is imposible to resolve this issue.
Let's see: the servlet container JRE has only one classloader, and this classloader can load and use one class from jaxb or the other, but not both that will give you a classdefnotfound exception or something similar.
You can not solve this directly:
you can get the code (is opensource) and change the package of one to another name so the classloader can use both. I do not recommend you this solution, is a bad one.
Better is that you migrate the code to use the most modern API (jaxb 2)
In my Java project I'm using two different frameworks (let's say A.jar and B.jar) and both of them require one common framework (let's say Log4j.jar) but in two different versions. How it is treated by Java if framework A needs Log4J v1.1 and B needs Log4j v1.2? Will it cause some kind of conflict/error or will by somehow (how?) resolved?
If it will not cause conflict/error (my project can be compiled and run) - can I use any version of Log4j myself in this project? Or am I forced to select lower / higher version number of Log4j?
Update: to be more specific...
What if some part of Log4j API changed in v1.2 (let's say one single method doIt() signature changed) and both A and B call doIt. What will happend? Will my project run? Will it crash on first use of doIt? What version of Log4j I must put on classpath - v1.2 or both?
In a flat class loading scheme, there is no library versioning support. You need to use the most recent version of the library and remove other versions from the classpath.
Some frameworks, like OSGi, provide mechanisms for handling these cases, but it isn't clear that you're relying on a plug-in framework.
Edit:
What if some part of Log4j API changed in v1.2 (let's say one single method doIt() signature changed) and both A and B call doIt. What will happen? Will my project run? Will it crash on first use of doIt?
A call relying on a signature that is not present will likely result in a NoSuchMethodError. This probably will not happen until the method is invoked. Other errors may occur if other mechanisms rely on the signature (e.g. class inheritance).
What version of Log4j I must put on classpath - v1.2 or both?
Making two versions of a library on the classpath will just result in one set of classes being loaded randomly. The behaviour will be undefined, but could potentially result in all sorts of unpleasant errors and exceptions.
Java doesn't natively support the management of multiple versions of the same piece of code, that is, you can only use at most one version within the same JVM (with the default class loader). However, checkout question 1705720, which has several answers pointing out possible ways of achieving that (OSGi or custom class loaders).
But I doubt it worth the trouble as multiple log4j versions are not required by your code directly. In you case, I'd suggest to start from using the newer log4j version (v1.2) first and verify if it would cause any problem for framework A. If it does cause conflict, then fall-back to log4j v1.1 and verify again. If you really are out of luck, then you need to get your hands dirty...
Update: for you specific description, there's no way of using either log4j v1.1 or v1.2, as framework A and B each require different signature. You have to roll your own version of any of log4j or framework A, or B.
If your lucky picking one version of the third party jar will just work. In the end one needs a container that understands and enables versioning of components all to coexist, something like OSGI.
Although not recommended but you can use both versions. Put each version in a place where only that framework can see.
The optimal solution will be to get the last versions of both A and B, where both use the last common libraries
In the Eclipse environment I have project A. A has dependencies to projects or libraries B and C. (does not make a difference if they are projects or libraries)
B has dependency on LibX.v1 and C has dependency to LibX.v2.
During runtime, A will need B.jar and C.jar. Also classes in B.jar will need LibX.v1 and classes in C.jar will need LibX.v2 .
Being the different versions of the same library, LibX.v1 and LibX.v2 has same classes, so it is possible that a class may be loaded from the wrong version of the library in the runtime, causing lots of trouble. How do I manage these kind of situations?
Kind regards
Seref
Really, you don't. Most Java classloaders don't give any guarantees about the order in which libraries will be loaded, so you really need to be sure not to duplicate dependencies on your classpath. I would check if B or C could be updated to a newer version, or if LibX is fully backward-compatible.
Edit: actually, I found something that may help you. It's called OSGi, and I haven't used it, but it seems like it might do what you're trying to do. Here is a link to an intro article.
you'll need to use a 'multiple classloader' mechanism (which is what OSGI is capable of). In such a scenario the classloader for class B can only see LibX.v1, while classloader C only sees LibX.v2.
You can it do it with OSGI, but OSGI is much more than this and it's not trivial to get started with.
another plug-in framework is JPF, which also offers more than just using multiple classloaders. i think they both use the principle of 1 classloader per plug-in (module, whatever, ...)
maybe have a look at classworlds. I think it's possible to do it with this library. the benefit is that it focuses on the classloading aspect. documentation is not so good. classworlds uses the notion of class realms. take a look at the API Usage example on the site.
i'll add an example here if i find one.
anyway, no trivial solution for this i think
solving it with dependency management is the best solution of course, but it's not always possible.