Why would you want to declare JAXB as a dependency of your Java application since it's anyway shipped with the JRE and cannot be overriden in your applications classpath?
Using the jersey-json as an example, in their POM file they declare a dependency to jaxb-impl without specifying the exact version even. What are they gaining by doing this?
And also, when I add a dependency to jersey-json in my own POM file, I end up having jaxb-api.jar and jaxb-impl.jar in my classpath. Why would I want this to happen? Isn't the default JVM implementation anyway getting loaded if I don't put the files to the endorsed libraries directory?
I'm seeing in the linked pom:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
But there is also a parent pom, so you might want to follow that trail up, to see if an actual version and/or scope was specified there (and propagated down).
But if it isn't, then I'm guessing the Jersey team felt that the JAXB 2 API is mature enough to allow them to specify a loose dependency on the JAXB implementation.
The JRE ships with a specific implementation of the JAXB impl, which was equivalent to JAXB RI 2.1.7 for the longest time. But at the same time, there is a mechanism to easily swap out for another implementation of your choice, in your apps.
Sure you can use the built-in JRE JAXB implementation, and if it works for your app, you surely should try.
Nonetheless, some reasons that could lead you to want a separate JAXB implementation include : a left-over bug (addressed in a newer release); need a newer JAXB API such as JAXB 2.2.x (which comes in more recent version of the JRE); want to use a different implementation altogether (because it happens to have a better API and/or performance for your particular usage), etc...
So back to your jersey question, I'm guessing again that they wanted to give developers the flexibility to pull in their JAXB impl of choice. I'd think they have some level of recommendations somewhere in their guides.
However, the fact that the JAXB RI is specifically marked as a dependency, undercuts the argument.
That sound like the jersey people defined their dependency wrong. If a dependency is provided by the environment where you run it should be defined with the scope "provided".
Related
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.
I am working on maven product that use some common-collection jar with version v3.2.1, which gets downloaded from our repository. Through out the project we are using ver1.1. Now I have to use third party jar which uses common-collection with v3.2.2 due to which I'm getting NoClassDefFound exception.
Exception in thread "main" java.lang.NoClassDefFoundError:
org/apache/commons/collections/map/ReferenceMap
I cant change the version in my project. How to solve this issue?
I cant change the version in my project which is v1.1
Now I have to use third party jar which uses common-collection with v3.2.2
You have a hard choice to make. Either change (upgrade) the version in your project, or don't use the 3rd-party library. (This assumes that the 3rd-party library's dependency is a hard one ... which seems likely if API classes have been moved, etcetera.)
The first alternative is probably better. The longer you stay on an outdated version of the commons-collection library, the more problems like this you will encounter.
Actually, there is third possibility but it is asking for trouble. You could try to build your own version of commons-collection that is compatible with both v1.1 and v3.2.2. But here's the problem:
You are buying into extra work maintaining this custom version of commons-collection, for as long as you need it in your codebase. (And that could be a long time if versions of your code are long-lived; e.g. if they released to customers who have long-term support requirements.)
It might not work. Suppose that one part of the code requires ReferenceMap in one package, and another part requires it in another package.
Another possibility (another bad idea!) might be to do tricky things with classloaders, but that can lead to problems as well. If you two versions of the same class are loaded by different class loaders into an application, the type system will insists that they are different types. They won't be assignment compatible. Type-casts will fail unexpectedly, etcetera.
seems it has been moved to
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
Background
I have a commons library that I have to update. This commons library has a third party dependency (jgroups) which was changed significantly in newer versions. Through transitive dependencies, the newer version of jgroups is sometimes required and this breaks the commons library. I need to update some classes for compatibility with newer versions, while maintaining backwards compatibility.
The Problem
JGroups provides a View class, which has a method getMembers(). In the old version (2.10.0), this method returns Vector<Address> and in the newer version (3.2.7), this returns List<Address>. Any implementation of java.util.Collection will work for me, but the problem is I'm getting a NoSuchMethodException. As I understand it, the getMembers() method found has the legacy Vector<Address> return type (based on the JGroups dependency in the commons library), but I am dragging in a newer JGroups version and that View class expects a List<Address> returned from the getMembers() method.
Stacktrace
I get the following error when starting up my application in Eclipse.
Caused by: java.lang.NoSuchMethodError: org.jgroups.View.getMembers()Ljava/util/Vector;
at com.mycompany.commons.messaging.events.impl.distributed.JGroupsEventDistributionProvider$JGroupsEventReceiver.viewAccepted(JGroupsEventDistributionProvider.java:136) ~[classes/:na]
at org.jgroups.JChannel.invokeCallback(JChannel.java:752) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
at org.jgroups.JChannel.up(JChannel.java:710) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
at org.jgroups.stack.ProtocolStack.up(ProtocolStack.java:1020) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
at org.jgroups.protocols.pbcast.FLUSH.up(FLUSH.java:466) ~[jgroups-3.2.7.Final.jar:3.2.7.Final]
....
Where it breaks
Collection<Address> viewMembers = view.getMembers();
Question
Is it possible to support both versions, even though they are different implementations of Collection? How can I handle this scenario where I don't know the method return type until runtime?
Note:
I have tried to exclude the older version of JGroups that is being pulled in by adding an exclusion in my maven pom. This has not worked.
<dependency>
<groupId>com.mycompany.commons</groupId>
<artifactId>mycompany-commons-event-distributed-jgroups</artifactId>
<!-- Note: JGroups dependency is provided by infinispan -->
<version>1.0.2-SNAPSHOT</version>
<type>jar</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>org.jgroups</groupId>
<artifactId>jgroups</artifactId>
</exclusion>
</exclusions>
</dependency>
How about using reflection ? Field View.members is a Vector in 2.10.x and an Address[] array in 3.x. You could access field View.members and - depending on its type - return all members as a collection of addresses. Not nice, but should work..
If you are using "plain java" for the app framework, I think you are generally out of luck.
Without using some sort of module framework such as OSGI, you only have a single pool of classes and every class loaded onto your classpath goes into that pool. This means you can't have multiple versions of the same JAR or the same class in your JVM at the same time.
Also, you must support multiple versions of the same JAR because you have at least two pieces of code compiled each against the different versions: one is expecting the return value of Vector and the other of List, so even if you could isolate the undesired one from your build environment, the code built against it would then not link to the proper binary and you will continue to get the runtime exception you see.
Unfortunately, you mentioned this is a "library" and not just a single app, which may make it even more difficult to apply a solution. Off the top of my head, I see these options for you moving forward, none of which are trivial and some may not be possible:
downgrade your code as necessary to only have a single version of jgroups in all dependency chains
rearchitect your app to use OSGI or a similar framework that supports multiple versions of the same library so dependency chains may diverge
rearchitect your app and fragment it into multiple that each run in their own JVM, communicating with sockets or any other means
For example, we have used the third option to split out a small portion of an app so it could depend on libraries with licenses unfriendly to our entire codebase but that portion could be licensed along with the library.
I am also not sure how the Java 9 module system would behave with this, but it might support multiple versions of the same module in the runtime simultaneously. If it's an option for you to use that beta or investigate, that may be worth your effort. However, you mentioned that the point was backward compatibility, so that may not be a viable option either.
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.
I'm trying to get my head around some concepts in Java:
JSR(s): describe specifications, but carry no actual implementations. E.g. http://jsr311.java.net/ is the "home" for "Java™ API for RESTful Web Services". It serves as a common reference for all implementations of JSR-311.
One can download the interfaces (?) of JSR-311 from http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, however, unless you are implementing JSR-311 by yourself these have no particular value?
JSR(s) will usually/always have a reference implementation. To find it you'll have to google "JSR XXX reference implementation" or see the specifications home page (e.g. http://jsr311.java.net/)
For JSR-311 this reference implementation is Jersey. Using maven you can get the jersey server from http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9. Since
Jersey provides an implementation according to the interfaces found in http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, you only need to add Jersey as a dependency in your project and not the jsr311-api itself. (this applies to all JSR technologies?)
Putting both http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api and http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9 as dependencies in your project will possibly cause classpath problems?
Am I completely off or onto someting?
Yes, this isn't anything new. Think about JDBC, java provides the
interfaces (Connection, Statement, ResultSet etc) but it is up
to database vendors to provide implementations.
If you're using a JSR-311 implementation like Jersey or Apache CXF
then you'll annotate your classes with the javax.ws.rs annotations, such as #Path, #GET, #Produces etc. This is why you need to explicitly have JSR-311 as a maven dependency.
Yes, usually. Have a look at the JSR list on wiki.
You need both the JSR and the implementation. The annotations are in the JSR, the implementation provides supporting classes, such as com.sun.jersey.spi.container.servlet.ServletContainer.
No, it is necessary to have both as dependencies (see point 4); you won't get classpath conflicts.
—
One can download files from a variety of sources. To get the most official version of the JSR-311 specification go to its JCP download page. It's quite possible that you can't get a JAR file (with all the interfaces and stuff) from JCP pages, but still, this is the official source. (There are always nice PDFs of public drafts also!)
—
You're right, because Jersey contains the API defined by JSR-311, however I would add a compile dependency to the jsr311-api JAR file and add Jersey as runtime dependency. This creates a nice separation between API and implementation and you can swap out your JSR-311 implementation anytime [sic]. If you intend to use Jersey all the way include only Jersey. One less dependency in your POM.
If Jersey packages the same API as the jsr311-api JAR contains, it won't. If it packages something different, well, that would be awful! Maven will probably bark at compile time if one has a corrupt JSR-311 API on its classpath (I've already seen lots of java.lang.ClassFormatError: Absent Code attribute in method that ... errors, so it won't go unnoticed, that's for sure).
Other than these, you're right.