Java dependency priority - java

Trying to figure out how will the JVM decide which dependency to use:
We have a gradle compiled fatJar, containing several dependencies, i.e. Jackson X version etc.
My app is a Play framework 1.x app, using the the fatJar artifact from stage 1, and other dependencies, including aws java sdk which uses Jackson itself, newer than X version.
How can I tell which Jackson version is used in runtime?
[It seems that on 1 env it uses the correct one, and on the other, aws sdk is using the incorrect Jackson]

In simple case when you provide classpath to java and do not use any classloader the answer is simple. It will search classpath in order you provide.
I strongly discourage you from relying on that behavior.
There is solutions for you problem. One of them to use OSGi it allows to use multiple version of libraries, but i must mention that it is heavy framework.

Related

ActiveMQ version 5.16.0 has vulnerable dependency jar

I am using ActiveMQ 5.16.0 downloaded from Apache. I see a few of the jars are older versions which have vulnerabilities, e.g.:
com.google.guava_guava 19.0
core_jackson-databind 2.9.10.4
shiro-core 1.5.3
log4j-1.2.17
I see all above vulnerable jars are located under apache-activemq-5.16.0\lib\optional\. What is use of jars under the optional directory? Is there any latest release of ActiveMQ which has all latest dependencies?
Optional dependencies are just that: Optional.
Using Shiro in your case as reference.
Optional Dependencies: Typically an optional dependency is not required for the core functionality of the library you are referencing. In this case, Shiro is only required if you intend to make use of Apache Shiro features or functionality. Shiro is used for security and therefore makes sense that it will not be used by everyone making use of ActiveMQ.
Versions: Many times (not always) optional dependency versions are not set in stone and it may be possible to use newer versions without breaking the functionality. This is not always the case, so if you aim to do this, start with the preferred version and only upgrade after the functionality is working to test.
Vulnerabilities: Simply because a vulnerability exists, does not make it applicable to your use case. Just because there is a known vulnerability in a dependency that can do XYZ, it will likely not affect you if your use case does not make use of XYZ. A security report such as the Apache Shiro one could help in understanding this.
Additionally: I would suggest that you look into Maven or Gradle for your Java projects. This will take away some of the need to worry about these types of dependency management issues as optional dependecies are not included in the dependecy hierarchy by default.

Maximum Reusability for Two Implementations with Different Dependencies

I have a task that includes migrating an API Gateway from Zuul to Spring Cloud Gateway. There are two main versions currently: 1.0.1.RELEASE and 2.0.0.RC1. The first version is very basic and I'd have to manually implement filters related to rate limiting, authentication, etc...
While the second version has all the features we need with complete YML support. We have a strict rule in the company to never use beta or RC, and we need the first version of the gateway to be in production within a couple of weeks so there is not enough time to wait for the final release of version 2.
My team-leader specifically asked me to make 2 versions of using version 1.0.1 and 2.0.0 of SCG. How do you implement the module for maximum reusability? I mean I want switching between the two versions to be as easy as possible and I want to reuse as much of the logic as I can. The first thing that came to my mind is simply to create two separate projects. What do you think?
As I understand the question, you want an easy transition from the version 1.0.1.RELEASE to 2.0.0.RC1 of some dependency.
I would approach it as follows:
Create 3 modules (or projects):
api
bindings-1
bindings-2
The api module contains the API which you'll define to access functions of the dependency.
The bindings-1 and bindings-2 both implement what's defined in api, but based on the versions 1.0.1.RELEASE and 2.0.0.RC2 accordingly.
Your code will use the dependency only and exclusively via the api. No direct access to the classes and methods provided by the dependency. I would even not include the dependency as a compile-time dependency. You'll then import bindings-1 or bindings-2 depending on which version you want to use.
Having a separate api will require certain effort. It will seem overengineered. But if you don't do this, bindings to the dependency will diffuse in your code and switching from one version to another will be much more difficult.
With a dedicated api you will be forced to crystallize everything you need from the dependency in your api - in a version-independent manner.
I would also not develop bindings-1/bindings-2 as SCM branches. It's not like you'll be merging them, so why branches?

WildFly RestEasy Version confusion

I want to build a REST API using RestEasy. The generated file should be deployed in a WildFly application server.
I face the issue described in the following SO-question:
AsynchronousDispatcher error
The marked solution tells me, to set the dependency to "provided". Which as far as I understand means, that the library is not included in my war file but taken directly from the app-server...
Isn't that just wrong?
My idea would be to build a self-containing war file which contains all the needed libraries in the version I need.
When provided from the app-server I do get the currently available version from there. I have not really a clue about the version... when someone has the idea to update the RestEasy library on the server, it might break my app.
I'm not sure whether I missed something or did something completely wrong?
One of the big advantages to Java EE is developing towards the API and not having to worry about the implementation. Java EE containers provide the API's and implementations for the API's. If you include implementation dependencies one of two things is likely to happen.
You're dependencies will be ignored making it pointless to include them in your deployment.
You'll get conflicts between the dependencies you included vs what the server is expecting. This could be things like:
ClassCastException because it's finding two of the same class on the class path.
MethodNotFoundException because there is a version mismatch
Various other issues with conflcts
Developing towards the API instead of the implementation also allows you to easily switch between Java EE compliant containers with no to minimal changes to your deployment. The API's are generally backwards compatible as well making version upgrades not as big of an issue.
If you want to use a fat WAR (including implementations) instead of a skinny WAR (not including the implementations) then a servlet container is probably a better solution. WildFly does have a servlet only download. I'd encourage you though to trust container to do the right thing with the implementation dependencies :). Usually the only time there is an issue with upgrading is if you're upgrading Java EE versions. Even then it's usually pretty safe.

Distributing a library built with Spring

I'm building a library that uses Spring 4.2.4 and am planning to bundle Spring with the library, to make a self sufficient jar with all dependencies included because some of my clients don't use Maven.
However, some of the clients using the library could be using a different version of Spring already in their applications, some as old as Spring 2.5. In this case, they would exclude the bundled version of Spring. Then how do I handle feature compatibility issues? For example, Spring 4 can have multiple PropertySources, and this is not supported in earlier versions.
Only if you really need to, you can bundle the libraries you want in your library and alter their packages to make sure that no collision or class loader conflicts happens in scenarios such as what you describe happens. If Maven is your build system, you could use the Shade plugin to accomplish this. Such an approach is taken in such popular libraries as Jersey 2 where the guava library classes are included in the distribution with modified package name.

Why Maven requires same version of different dependencies?

I'm a student with quite some experience in Java but totally new to Maven.
I was trying to implement a RESTful service provider and client with jersey-server and jersey-client. Both also depends on jersey-json, to make use of automatic conversion between POJO and JSON. Both of them also depend on a service model I implemented myself, where the POJO definition resides.
However, the code doesn't work for me. I spent quite a few hours looking for solutions everywhere on the Internet. It turns out the reason of the failure is that I accidentally specified version of jersey-server and jersey-client as 1.14, but jersey-json as 1.9.1.
The server doesn't work at the beginning, but at some point suddenly starts working. (I have no idea how this happened.) The client never worked until I change jersey-json version to 1.14.
Why do I need to have the same version for these different dependencies?
Because one depends on the other or otherwise has a compatibility issue. This is what dependency management is all about. Run mvn dependency:tree to see exactly how these libraries relate to each other.
In this case, it seems Jersey libraries are all released together as a "bundle" - and you need to use the versions from those bundles together. See: http://jersey.java.net/nonav/documentation/latest/chapter_deps.html
Note that this is an attribute of the Jersey libraries, not Maven.
Often different jars from the same distribution are tested together and given the same version number.
If you try to mix different versions it might work, or it might not, as its not a combination which was intended or tested.

Categories