Maven BOM dependencies in Gradle - java

Given that there is a BOM listed in the dependency management of a Maven project Foo like this:
<groupId>someGroup</groupId>
<artifactId>someArtifact-bom</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
but this BOM comes only into play for a test dependency in a sub-module.
<dependency>
<groupId>someGroup</groupId>
<artifactId>someArtifact</artifactId>
<scope>test</scope>
</dependency>
The artifact declared in the BOM and BOM itself are only available by declaring an additional repository.
If I create a new Maven project and declare the dependency to Foo it gets resolved.
In case I define the very same dependency to Foo in a Groovy project
repositories {
mavenCentral()
}
dependencies {
implementation("myOrg:Foo:1.0")
}
The resolve fails with
- Could not resolve myOrg:Foo-parent:1.0.
- Could not parse POM <mvn-central>/myOrg/Foo-parent-1.0.pom:
- Could not find someGroup:someArtifact-bom:1.0-SNAPSHOT.
...because it does not exist on central.
Of course it can get easily solved by adding the repository, if accessible from the user's project, or putting the BOM and its declared artifacts on central.
I wonder if there are another approach that I couldn't come up with to avoid this problem in the future. An exclude on the dependency definition does not work for BOMs. I can understand this behaviour because a BOM is not a real module.
Just for completeness: After a correct resolve there is no dependency regarding the BOM or its artifact in my project. It is really not needed at all.

To be complete, what you experienced with Gradle looks like the expected behaviour to me.
Gradle will not dynamically add repositories defined by dependencies. This is because it can become a security risk where an added repository could attempt to shadow popular packages with poisoned artifacts.
So the right solution in Gradle is to add the extra repository when required.
With a number of changes that went into how Gradle interprets BOMs and loads Maven POM files, it could very well be that since the BOM is not required, more recent Gradle version will happily ignore it.
But the root problem, transitively adding random repositories, will not be done by any Gradle version.

Thanks to the comment of Corneil du Plessis I took a deeper look in trying out different Gradle versions and a newer one fixed the problem.
Going back later to the original version that made me aware of the problem (5.2.1) it kept resolving the dependency without any error.
To be really sure I cleared the local Gradle caches and re-ran the build with success.
Since I cannot reproduce the issue anymore with either 5.x nor 6.x I am pretty sure that this was related to the cache and the history of Gradle on my machine.
I think it makes sense to answer my question by myself instead of just closing it to leave the information here.

Related

Maven plugin dependency conflict

I have a bit of a thorny maven dependency problem. A plugin in a parent pom.xml requires guava v10 and a dependency in the module I'm trying to build requires guava v18. Not exactly sure how to proceed as both are needed but maven resolves in favor of v10, which crashes the dependency at runtime. I tried skipping the plugin as outlined here (although I'm not sure if it's a good idea), but that didn't help. How do I dig my way out of this?
Please reference to this post and try to use exclusion to exclude the guava version you don't want to use

Maven - installed to local repo, not getting transitive dependencies

I have a maven project that I'd like to share with several of my other projects. It has some custom code, and then a few dependencies on things like log4j, jasypt, etc.
I build it and install it to my local maven repo. I can see it's successfully put there. Looking at .m2/repository/derp/Foo/1.0 it has a .pom with all its dependencies defined.
I can also define it as a dependency in my higher level projects, and it compiles.
<dependency>
<groupId>my.group</groupId>
<artifactId>Foo</artifactId>
<version>1.0</version>
</dependency>
I can see the Jar in my 'Maven Dependencies' in eclipse, and expanding that jar I can see it has the correct pom with dependencies in META-INF/maven/derp/Foo/pom.xml.
But my top level project above Foo isn't getting the dependencies that Foo needs. I get runtime exceptions, and I can see none of the transitive dependency jars are in my maven dependencies in eclipse.
What do I need to do to make sure Maven knows to look at the Pom for Foo in my local repo, so it will get all the transitive dependencies it needs?
----- edit -----
Answer to comment below, they are defined like this, with the dependencies tag at the top level under the project tag.
<dependencies>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.2</version>
</dependency>
etc...
These are the jars that maven correctly finds when I am just building and running this Foo project, but maven doesn't include these jars if a project depends on Foo, (Bar), and I find out when I try to run Bar.
What does "top level project above Foo isn't getting the dependencies" mean?
Anything "above" Foo in the build reactor should depend directly on Foo as you have stated. The <dependency/> specified will resolve to Foo's dependencies (within the scope that Foo specifies).
Without understanding the specifics of your project, it's improbable that we can to help you any further.
Some possible common situations:
You expect to be able to get access to test scoped dependencies in some non-test phase of execution. Just not true.
You expect that specifying a dependency on an artifact causes the java runtime to load those dependencies for you automagically. That's also not true. You'll want to invoke the exec:java goal on the maven exec plugin and specify your desired resolution scope within the <configuration/>, possibly also for that <execution/>.
You've mistaken <dependencyManagement> for <dependencies>. This happens way more than I would have expected.

New maven dependency version pulling pom, not jar into private nexus repo?

I'm upgrading some dependency versions I have in a java/maven/spring application, which is using our nexus repo as the central repository mirroring maven central.
I tried upgrading hibernate to it's newest version of 3.5.4-Final as listed:
Hibernate newest release stable version
And when I run maven install, I see in my nexus server that there is now 3.5.4-Final listed, but inside its directory there is only a pom.xml file for the project and none of it's associated JAR's.
When I inspect the POM, I can see it's packaging is listed as POM and not JAR.
Why is this, and how can I make maven take the jar packaged version of the library rather than just the POM?
EDIT - mvn install error message posted:
[ERROR] Failed to execute goal on project app: Could not resolve dependencies for project com.app:app:war:16.2.1-SNAPSHOT: Failure to find org.hibernate:hibernate:jar:3.5.4-Final in http://ssp-nexus1.mynexus-server.com:8081/nexus/content/groups/public was cached in the local repository, resolution will not be reattempted until the update interval of company.nexus.mirror has elapsed or updates are forced -> [Help 1]
As mentioned in the link you provided
Aggregator of the Hibernate Core modules.
So, the artifact you linked is effectively a pom which aggregates (as a multimodule) other Hibernate artefacts.
Instead, the hibernate-core artifact, as an example, can be found here, as a standard maven dependency (that is, a jar).
By default dependencies have type jar, so if you add the maven coordinates (GAV) for a dependency that is instead of type pom, maven will then look up for it as a jar. So that's why you are getting the error mentioned in your edit.
You should remove its dependency from your pom and only add the hibernate dependency you effectively need. As a rule of thumb, add the dependency you explicitly use in your code (as import statements, for instance) or your configuration files, and let then maven take care of the required transitive dependencies, given that they will be available on your company repository, obviously.
Update
Following your latest comments and feedback, here is a further explanation about why just changing the version of the existing Hibernate dependency you got to this issue:
The new 3.5.4-Final and the previous 3.2.7.ga version share the same groupId and artifactId on the Maven repository
However, the former has type pom (it's a pom file), while the latter has type jar (the default one)
So, the previously existing version was working fine and changing the version of the dependency you switched it from jar to pom, breaking the maven resolution (which was looking for a jar for a version which instead was a pom)
This mainly happened because you switched from a ga to a FINAL version. For a further explanation about the difference between these versions, you can check this SO question and this one
As a side note, I find a bit inconsistent that changing a version number also changes the dependency type, it might a point of debate, but if I were the Hibernate team, I would handle this version management differently.

Unknown small library (ex. webhdfs-java-client) in maven not found

I am trying to implement a little service in Scala using Maven to manage dependencies and I would like to add webhdfs-java-client that I have found at https://github.com/wdavidw/webhdfs-java-client
I have added to pom.xml following code:
<dependency>
<groupId>org.zxs</groupId>
<artifactId>webhdfs-java-client</artifactId>
<version>0.0.0</version>
</dependency>
It does not work, as I have expected. Does anyone could give me an advice if there exists some catalog of maven repositories (something like pip for Python)? And what can I possibly do if I'll not find this library in the catalog? Is it possible to somehow add it to maven manually?
In maven world you can install this dependency locally and resolution will be done via local cache (the one that usually resides in ~/.m2). Steps are as simple as mvn clean install in that repo. Having said this, it wouldn't resolve problem for your users (transitive dependencies, you know), which is why you likely need to publish that dependency somewhere (or ask library author whether it's published somewhere).
SBT, which is scala's de-facto build tool allows you to depend on other sbt flavored projects simply by referencing their git repository, but sadly, maven has no such feature.

Introducing dependency breaks existing dependency?

I'm working on a project that builds and deploys fine. I'm trying to add some code that uses JWebUnit, and use the following Maven code to bring it in:
<dependency>
<groupId>net.sourceforge.jwebunit</groupId>
<artifactId>jwebunit-htmlunit-plugin</artifactId>
<version>3.2</version>
<scope>test</scope>
</dependency>
Maven seems to resolve this fine and it's bringing everything in (I'm using Intellij, and it now appears under 'Dependencies' in the 'Maven Projects' tab, and also under 'External Libraries' in the Project tab).
However, when I bring this dependency in, the IDE is not able to find it (e.g. if I use import net.sourceforge.jwebunit.junit.WebTester, it can't find it).
But an even bigger issue is it actually breaks some existing code -- I have some JUnit tests that use org.apache.commons.httpclient.HttpClient, and now on Maven's install goal I get a
NoClassDefFoundError - Could not initialize class for that class.
If I remove the JWebUnit dependency, the Maven install goal exits successfully.
I'm used to seeing errors about dependency version convergence when bringing new dependencies, and I feel like chasing this 'no class def found' error could be a red herring, but I'm not sure of the general types of issues in Maven that could be causing it.
EDIT: the dependency code for pulling in HttpClient is:
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
jwebunit-htmlunit-plugin includes transitive dependencies which seem like they're conflicting with some of your dependencies (likely because they are different versions).
Maven puts classpath priority on artifacts declared earlier. Try moving jwebunit to the end of your dependencies section, or at least after where you pull in the httpclient classes. Alternatively, you can manually exclude certain transitive dependencies from being pulled in, but this can be tedious.
As for your IDE not allowing imports on the library, remember that you have this declared in the test scope. Production classes cannot see test dependencies.

Categories