GWT (Maven) project: Dependency conflict - maven

I have a GWT project with the following dependencies
<dependency>
<groupId>com.google.gwt.inject</groupId>
<artifactId>gin</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>net.sourceforge.owlapi</groupId>
<artifactId>owlapi-distribution</artifactId>
<version>4.0.2</version>
</dependency>
gin 2.1.2 depends on guice 3.0 while owlapi 4.0.2 depends on guice 4.0-beta.
gin is used on the client side while owlapi is used on the server side.
Compilation fails when I force guice 4.0-beta to be used. Caused by java.lang.ClassNotFoundException: com.google.inject.internal.util.$Maps
Compilation succeeds when I force guice 3.0 to be used, but fails at run-time caused by java.lang.ClassNotFoundException: com.google.inject.internal.guava.collect.$ImmutableList
Downgrading the version of owlapi is not an option.
What options do I have to make this work? Can I use dependency scopes somehow while still retaining a functioning GWT DevMode?

Split your project in distinct modules. Given Maven's limited (by design) dependency scoping options, this is really the way to go.
Use one module for client-side code, using only client dependencies (GIN with Guice 3), and one module for server-side code, using only server dependencies (OWLAPI with Guice 4); and have your client module compile your code to JS and package them as a WAR, that you can use as an "overlay" in the server module (or possibly use a third module that depends on both client and server if you prefer). If you have shared code, use a third/fourth shared module that both client and server modules depend on; the shared module would call maven-source-plugin's jar-no-fork goal so the client module could depend on the shared sources.
You can find archetypes following this approach at https://github.com/tbroyer/gwt-maven-archetypes. They use my Maven Plugin for GWT, but earlier versions (you'd have to clone and mvn install the project then from the appropriate commit) relied on Mojo's Maven Plugin for GWT (my plugin is designed with multi-module projects in mind, and removed a lot of hacks that were needed previously when using Mojo's plugin).

This is a complex scenario for my maven experience with scopes for dependencies.
Given that the error you get mentions guava, you may get lucky forcing the latest guava to be used - owlapi should work with 17 or 18.
Another option might be to try and recompile gin with guice 4 (and maybe contribute the changes upstream). I've got no idea how hard this can be though. You'd also have to ensure your snapshots are released with your app and accessible to others in your team who might need them.

For what it's worth. I spent a few minutes and "ported" it over to guice 4.0. Luckily it was pretty easy. I mavenized it otherwise there were virtually no changes to the code base.
https://github.com/chinshaw/google-gin

Related

How to fix org.projectreactor vulnerabilities on Spring dependencies?

I discovered some vulnerabilities in a Spring project that use dependencies:
reactor-netty-core
reactor-netty-http
The only related import I have in the pom.xml file is:
<dependency>
<groupId>org.projectreactor</groupId>
<artifactId>reactor-spring</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
After some research, I found that there is no new version for this dependency on MavenRepository, but that there is another dependency with the same name (projectreactor).
The difference is that this dependency starts with .io instead of .org.
https://projectreactor.io/docs/core
https://projectreactor.io/docs/netty
Can you help me to understand the difference between .io and .org in this case?
And what is the best way to update this to prevent these vulnerabilities?
Have you found a vulnerability (as in security research) or do you get eg. tooling reporting a known vulnerability?
Both Spring projects and Reactor follow VMware security policy. If you've found vulnerabilities, this is the channel through which you should report them.
The reactor-netty artifacts are part of the 3rd generation of Project Reactor (the current one, with io.projectreactor base groupId).
The org.projectreactor groupId is for the 2nd generation. Reactor 2 is long discontinued (early 2015) and unsupported since then. Reactor 2 and 3 can basically be considered two entirely different libraries.
It is very weird that you'd have an application which uses reactor-netty-* and reactor-spring at the same time. If you are dealing with a Spring Framework 5 application, you can probably simply drop that dependency.

What does it really mean that api configuration exposes depedencies whereas implementation does not, in Gradle?

I have gone through the official doc and many StackOverflow questions about the difference betweenapi and implementation configurations. I think I understand the basic, but I really want to understand what it means by dependencies are exposed or not exposed.
This is what I have got so far. When I publish my Java library (written in Kotlin, but not relevant), the dependency scope in the published pom file is either complie when api is used or runtime when implementation is used, i.e.
dependencies {
api "..."
}
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<scope>compile</scope>
</dependency>
dependencies {
implementation "..."
}
<dependency>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<scope>runtime</scope>
</dependency>
So does exposing dependencies in this case really just mean adding them to classpath (compile scope)?
One of the many answers about api vs implementation says it is merely about build optimization, it makes sense that the build time will be reduced if we not adding everything in the classpath maybe?
And a bonus question, the Gradle doc says api configuration comes with java-library plugin, but apparently, I can use it without applying the plugin, how is this possible?
// Gradle 6.1.1
plugins {
id 'org.jetbrains.kotlin.jvm' version 'XXX'
}
dependencies {
api "myLibrary"
}
So does exposing dependencies in this case really just mean adding them to classpath (compile scope)?
Yes, it's pretty much just a matter of having them on the consumer's compile classpath or not.
One of the many answers about api vs implementation says it is merely about build optimization, it makes sense that the build time will be reduced if we not adding everything in the classpath maybe?
Well, good software design advocates not exposing internal implementation details. This is why you have public and private class members in the code. You could argue that this principal is solid when it comes to dependencies as well. I see the following benefits:
A consumer does not implicitly start relying on "internal" transitive dependencies. If they did, it would mean that you can't remove them from the library without breaking the consumers.
A reduced classpath may make compilation slightly faster. I don't think it matters a whole lot for normal projects though. Maybe it is more impactful if you rely on Java or Kotlin annotation processors or Groovy AST transformations that feels like scanning the entire classpath through each time.
Not having unnecessary modules on the compilation classpath means a library will not have to be recompiled if those modules changes.
The last one is the biggest benefit in my opinion. Let's say you have a big multi-project where a shared sub-project internally relies on Apache Commons Lang. If you have declared Lang as an api dependency and update it, then all other projects relying on this shared project need to be recompiled. If you declare it as an implementation dependency instead, this will not happen. All those projects will still need to be re-tested of cause as the runtime behaviour might have changed (this is handled correctly by default in Gradle).
And a bonus question, the Gradle doc says api configuration comes with java-library plugin, but apparently, I can use it without applying the plugin, how is this possible?
This is because the Kotlin plugin also declares an api configuration. It has the same semantics as configured by the java-library plugin.
If your project is a multi-project, you can still add the java-library plugin even if it is using the Kotlin plugin. An additional change that this will cause is that consumers will see the output directory for the compiled classes instead of the final jar file. This removes the need to construct the jar during normal development, which should reduce build time. On the other hand, there is apparently a potential performance problem on Windows if you have a lot of classes in a single project, so the usual your mileage may vary disclaimer applies here as well (I don't know how many "a lot" is though).

Dealing with other dependencies in your own Maven dependency

I want to reuse and centralize the utils I created for my Spring REST API for my future projects. That's why I thought I'd outsource them to my own project and make them available as a Maven dependency.
These Util files e.g. a basic service, basic controllers also contain Spring annotations, i.e. I need some Spring dependencies in my Util dependency. Now I'm a bit unsure whether I'm making a mistake or not.
First of all, I'm not sure if I should even use spring dependencies in a utility dependency or try to remove everything. Otherwise, I'll have to specify a spring version, but it might differ from the version I want to use later in the project it's included in. How am I supposed to solve this?
It is perfectly reasonable to have dependencies for your dependencies (these are called transitive dependencies). Of course, you should keep the number as low as possible, but on the other hand, you do not want to reinvent the wheel.
When somebody uses your dependency, they will automatically draw the transitive dependency on spring. Now, several cases can occur:
If this is the only reference to spring, the version is just used as you stated it.
If at some other point, a different version of spring is given, Maven dependency mediation kicks in. It decides by a "nearest is best" rule which version to take.
But: You can always set the spring version in <dependencyManagement> and then overwrite all transitively given version numbers.
That is the main concept of Maven. Your utility module must shipped together with Spring dependencies. It's called transitive dependencies.
Try to imagine that situation when all dependencies had excluded. In that case nobody will never know what kind and which version of Spring dependencies are needed.
Maven has a very good dependency conflict resolution. It's based on nearest-newest principle. So you can override those Spring versions easily and your application will use only one of that.
Take a look at these:
[1] Dependency Mechanism
[2] Dependency Mediation and Conflict Resolution

How to fix errors caused by two identical jar with the same name but different versions?

In the project, there are two modules: data and infrastructure.
Data module uses the grpc plug-in provided by Google: grpc-protobuf, which refers to com.google.guava:guava [version:26.0-android].
Infrastructure module uses consul's plug-in: consul-client, which refers to com.google.guava:guava [version:22.0].
And the data module depends on the Infrastructure module.
There is no problem at compile time, but at run time, ConsulCache in consul-client calls the Stopwatch.elapsed() method in com.google.guava:guava, which is no-argument in com.google.guava:guava:22.0 and parametric in com.google.guava:guava:26.0-android. ConsulCache always points to com.google.guava:guava:26.0-android rather than com.goog.guava:guava:22.0, which will report the following exception:
java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.elapsed()Ljava/time/Duration;
at com.orbitz.consul.cache.ConsulCache$1.onComplete(ConsulCache.java:103)
Because it's a maven project and it's all about automatically managing jar packages, it's automatically referenced by third-party plug-ins themselves.
How to fix this exception without modifying their source code?
First of all, you need to decide if you want version 22.0 or version 26.0-android.
Then you add a <dependencyManagment> entry to the poms (or the common parent pom, even better) that manages com.google.guava:guava to the version you want.
The dependencyManagement (https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management) overwrites all transitively found version numbers of that dependency. So you only get the version you choose.

spring 4 security jars are missing for offline download

while working on spring mvc 4, how to find the jar for offline project like the jar Spring Security Config,spring-security-web for spring 4 ... etc as thet are not available with default package of jars and I do not want to use maven at this time so where one can find the jar for spring 4
?
First of all, foregoing proper dependency management is a bad idea and will make development that much harder, especially when it comes to transitive dependency resolving.
However, if you really want to do it then you can download .jars straight from Maven Repository or any other online repo that hosts them.
If that fails then a Google search will give you some source to download them from.
Trying to avoid a dependency management tool that to with a framework like Spring which complements many other frameworks is a bad idea in the long run. It will be painful to upgrade the versions in future.
But if you still don't want to use maven/gradle kind of build tool, just use pom.xml/build.gradle just for onetime use and let maven/gradle download all the dependencies and copy all those jars in some folder of your code.
Again I strongly suggest to use a build tool, especially for Spring. Maven/Gradle are not that bad if you don't want to do crazy things!!

Resources