If a library declares provided dependency on eg servlet-api using v3.0.1; would it be possible for users to use version 2.5 for their library, that will be used on third party web application?
In other words:
mylib (srv 3.0.1) <-- some_framework(srv 2.5) <-- user_webapp (tomcat 6 or 7)
Moreover: v2.5 is declared as javax.servlet:servlet-api:2.5 and version v3.0.1 is declared as javax.servlet:javax.servlet-api:3.0.1, so there is a difference.
Would it be a problem for some_framework to specify different servlet-api dependency (eg 2.5) than defined as provided in mylib (eg 3.0)? I assume that since scope is provided (and available only in compile time), dependency tools (mvn, gradle...) will not download it in some_framework, and they have (and are allowed) to declare dependency manually.
(yeah, i am aware of differences between 3.0 and 2.5, and that is not a question. I also assume everything compiles correctly, etc. I am just interested how maven would compile some_framework, on which dependency: 2.5 or 3?).
Let me answer my own question, as [SO] never helped with tricky ones:)
I created simple maven project (that will act as some_framework). It depends on jodd-servlet (mylib), that has servlets 3.0.1 listed as provided dependency. When I run
mvn dependency:resolve
i do not see servlets in the list of dependencies. Now, if current project (i.e. some_framework) lists servlets v2.5 as dependency; and then if I run the same command again, I see only dependency on 2.5.
Therefore, we may say that provided dependencies are not transparent or exported.
Related
The project I am working on produces a jar that I deploy on azure so Spark runs the job.
It is using an internal dependency A which uses the dependency org.apache.commons:commons-configuration:1.10 yet when I deploy on azure it uses 2.1.1 version by default.
On azure we have the version 2.1.1 in which the package name(org.apache.commons.configuration2) differs from the 1.10 version ( org.apache.commons.configuration).
So having this line in the dependency A caused an error when using the 2.1.1 version:
Import org.apache.commons.configuration
It needs to be having "2" at the end, a thing I can t add as A is a dependency.
I tried excluding org.apache.commons:commons-configuration from A then using the maven shade plugin to rename the package but the jar file become double the actual size besides the shaded jar produced alone not inside the zip with the workflow and the sh file, a thing my team may not like.
Updating from commons-configuration 1 to 2 is a major change, the new version is not a drop-in replacement. As you have already pointed out the top level package changes and this will most likely brake library A. The correct solution will probably be to update library A to use commons-configuration 2.
You can still try to hack the Maven project setup to see if it works:
Exclude commons-configuration 1 from library A dependency using <exclude> tag.
Add commons-configuration 2 as a direct project dependency with provided scope in module B. The provided scope is needed to avoid packaging the dependency.
If you want to avoid using the maven-shade plugin than an alternative solution might be to:
Exclude commons-configuration 1 in the library A dependency declaration;
Work out which classes and methods from commons-configuration 1 that library A uses (easy enough if you have the source code, otherwise a modern IDE will disassemble it for you);
Write your own versions of these classes and methods in your application that delegate to the commons-configuration2 implementation.
Note that commons-configuration2 is a part of the Apache Spark distribution and it cannot be ignored. It would need to be added to your project with <scope>provided</scope>.
If this is too hard then the maven-shade-plugin is your only viable solution.
The module declaration defines, among other things, a module's dependencies. If I use Maven as a build tool, this is redundant because the pom.xml already contains these (and more) information. Based on that, couldn't Maven generate the module-info.java for me?
One might expect that most of the dependencies are indeed required modules as well. However, requirements can also point to modules of the JDK/JRE, which are not specified in the pom.xml. So yes, if you only look at the dependencies, probably most of them could be transformed to a required module reference.
But a module-descriptor contains much more information, which are all based on decisions to be made by the developer.
I've written an article about it which describes in detail why it is not possible to fully generate this file.
As far as I know, bnd-maven-plugin can generate module-info.class based on the configured dependencies. If you are working with maven-bundle-plugin, you need to specify the version of bndlib manually, for the latest version of maven-bundle-plugin(5.1.3) is still using the 5.x version of bndlib, and bndlib requires 6.x to support jpms.
Document: https://bnd.bndtools.org/releases/6.1.0/chapters/330-jpms.html
This question may have an answer already but I couldn't find a satisfying one. I just updated jersey jars to the latest one. I get jersey dependencies form the Parent project which also contains another project as a dependency which uses the lower version of jersey. I am not updating the jersey jars in this project. After updating the jars I see two versions of jersey client one of the them is the latest and the other one is from the project which uses the lower version.Scope is compile. My app is running fine but on the lib folder I see two version of jersey client 1.17 and 2.25.1. Will this cause any issue or Maven will always use the 2.25.1?
Thanks
Maven will always take the dependency which is the nearest to the root of your dependency tree. If two different versions are on the same level, the first one which is declared will be taken. Lets take the following example:
pom.xml
|--A:1.0
|--B:1.0
| |--A:2.0
| |--C:1.0
| |--D:2.0
|--C:2.0
|--D:1.0
Here, the libraries A:1.0, B:1.0, C:2.0 and D:2.0 are resolved. While the versions of A, B and C are taken because being nearest to the root, the version of D is taken because it was declared first.
I want to build a library as a Maven project that depends on some Spring libraries (version 3).
I want this to be used in projects that are also using Spring 3 - but I don't want the versions to clash, otherwise we'll have both versions of the spring libraries on the classpath.
I want to get the minor version for my library pom.xml from the enclosing project.
My question is: Is it possible to have a Maven library that inherits a dependency minor version from the enclosing project?
I believe you are worrying about something that is not going to happen. Conflicting versions between different dependencies on the same artifact will be resolved by a process called dependency mediation, and Maven will not pull in multiple versions of the same artifact onto the same classpath. E.g., if you make your library your-group:your-library:1.0 depend on org.springframework:spring-context:3.2.4.RELEASE, and my project my-group:my-artifact:1.0 depends on both org.springframework:spring-context:3.1.4.RELEASE and your-group:your-library:1.0, then Maven will only pull version 3.1.4 of spring-context into my build, not both 3.1.4 and 3.2.4. If your library also depends spring-beans:3.2.4 and there happens to exist some incompatibility between spring-context:3.1.4 and spring-beans:3.2.4, then you can consider it the responsibility of my project to add spring-beans as a dependency and explicitly override its version to 3.1.4 in my-artifact's POM.
That being said, you can sort of accomplish what your question is directly asking by using version ranges:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>[3.0.0.RELEASE,3.2.16.RELEASE]</version>
</dependency>
This will effectively tell projects depending on your library that your library is okay with any existing 3.X version of spring-context, but version ranges have their own set of rules during dependency mediation that can possibly be unfriendly and obscure, and they won't link up between different artifacts either, so I would recommend just sticking with a regular version number in your case.
Not really, no.
Are you happy to declare variables in the parent pom for this purpose? If not, then you'll have to create variables in your project pom or in a new parent pom that inherits from the enclosing project. ${project.version} and ${project.parent.version} aren't built from other variables and you can't compose/decompose them; you would need to duplicate those values into other variables and build your version string from those variables.
And even when you do that, maven will complain about version not being a constant.
The normal pattern in this case is to completely ignore the parent version and maintain your project's version independently: just because your project uses Spring 3 doesn't mean that it shouldn't start at version 1. You can manually track the parent version if you want to. Since your project is not part of the parent project, the maven convention of omitting ${project.version} and inheriting it from the parent project is probably not appropriate.
Imagine a are writing an application that has 2 dependencies; lets call them dependency A and dependency B. You have no control over either of those dependencies; they are not your libraries, but your application depends on them none-the-less. It turns out that dependency A has a dependency on dependency X (version 1.0); and B has a dependency on X (version 2.0).
According to the Maven documentation, Dependency mediation will be used to decide which dependency to use:
Dependency mediation - this determines what version of a dependency
will be used when multiple versions of an artifact are encountered.
Currently, Maven 2.0 only supports using the "nearest definition"
which means that it will use the version of the closest dependency to
your project in the tree of dependencies. You can always guarantee a
version by declaring it explicitly in your project's POM. Note that if
two dependency versions are at the same depth in the dependency tree,
until Maven 2.0.8 it was not defined which one would win, but since
Maven 2.0.9 it's the order in the declaration that counts: the first
declaration wins.
So, presuming we declare dependency A first, then X version 1.0 will be used in our application. This means dependency B will be using X version 1.0 at runtime, where as was compiled against X version 2.0. If B is using some 2.0 only features, then we will get a run time error (NoSuchMethodError, ClassNotFoundException etc.), that's not good.
So to "fix" this, we can exclude dependency X from dependency A, so that X version 2.0 is used instead. But oh no! X version 2.0 isn't backwards compatible, so we end up getting run time errors from A instead.
As far as I can tell, there is no way to fix this properly with Maven. All you can do is hope to get hold of the source code of one of the libraries and fix it your self. Is that correct?
Why is it not possible for both versions of the X to be packaged into my application, such that A uses X version 1.0, B uses X version 2.0, and the version of X available in my application is whatever Maven chooses through dependency mediation. Is it a limitation of Java, or a limitation of Maven? Is this situation common? Are there any other possible solutions? Should all libraries guarantee backwards compatibility to avoid this problem?
Two classes with the same name cannot be loaded into one class loader. If Maven allowed you to have multiple versions of the same artifact, this would undoubtedly occur. So this is a Java problem that Maven is accommodating.
I'm not sure there's a catch-all solution to this. If you controlled A or B, you could use shading to rename your usage of X to something that wouldn't clash, as described in What is the maven-shade-plugin used for, and why would you want to relocate java packages?.
In general one has to hope that backwards compatibility is maintained between the libraries and test the resulting application well to ensure there are no problems. Obviously you would want to configure Maven to include x-2.0 rather than x-1.0, either by listing B first or by explicitly listing X in your POM.
A word of warning: most version naming schemes allow breaking changes between 1.x.x and 2.x.x, so you may encounter problems. Some Maven projects (such as Apache Commons Lang) will use a new artifact ID and package structure when they change major version in order to avoid these conflicts.