SBT - Transitive dependency clash - scala

I am building a library L at my company for an old project P that we cannot touch.
The library is bringing a dependency Dv3 which have an incompatible version with something that the old project is using Dv1.
How can I build L so it is hiding Dv3 from P ? I know it is probably not good practice but there are not many options here.
Thank you

Related

Dependency upgrade along with transitive dependencies

I have quite a big Play/Akka project on Scala 2.11 with literally dozens of dependencies, for which we need to migrate to all new stack: newest Play, Akka, Scala etc.
But along the upgrade way, our team constantly facing unexpected issues after certain lib update that another lib has transitive dependency on it, which was evicted and suddenly starting to crash in runtime somewhere in internals. E.g. play-pac4j has transitive dependency on Play, which we forgot to upgrade properly after Play upgrade from 2.5 to 2.7.
Question: is there any sbt plugin, which can say in advance which dependencies I need to change to which version version, if I want to update dependency group % name from version-x to version-y?
I'm aware of sbt-dependency-graph plugin and we are using, but I want some automation. Meaning: sbt-dependency-graph has whatDependsOn command, but I don't want to manually verify which version is compatible with transitive dependency i want to go to.
Thank you.

How to create a package that is most likely not to cause versioning problems?

I created a NuGet package with an empty logger and my package depends on Microsoft.Extensions.Logging.Abstractions.
My PackageReference line and my dependency in the .nuspec file are set to 1.0.0 with no special syntax which I understand means >=.
My empty logger works just fine with this version and I thought using the lowest working version of the abstractions lib would make my package easier to consume by applications which are likely to have greater versions.
However, when I've referenced my package from an xUnit test project I have a red compiler error CS1705.
My test project references two packages:
The project its testing, which is an ASP.NET Core Razor Pages site that in turn references the same logging abstractions package which is included in Microsoft.AspNetCore.App 2.2.0 metapackage.
My empty logger package, which, in turn references the logging abstractions 1.0.0.0 as I have described.
Compiler error from the test proj says:
Assembly (Razor Pages proj) uses (Abstractions 2.2.0.0) which has a higher version than referenced assembly (Abstractions) with identity (Abstractions 1.0.0.0).
My package can use the higher version so what am I missing?
Edit
Here's a high fidelity diagram ;)
T is "xUnit Proj".
W is the "Website Proj" under test.
E is the empty logger package (Evoq.Instrumentation on nuget.org)
A is metapackage Microsoft.AspNetCore.App 2.2.0
L is Microsoft.Extensions.Logging.Abstractions
There's the nearest wins rule, which I think means that the dependency from T to L via E would win and version 2.0.0 would be used but I'd expect a package downgrade warning not a hard compiler error.
Nearest wins: https://learn.microsoft.com/en-us/nuget/consume-packages/dependency-resolution#nearest-wins
Edit 2
It just occured to me that T > W is a project reference. So maybe that's short-circuiting the NuGet resolution. I'll add a ref from T to A directly and see if that solves it.
I forgot T > W is a project reference. So I think that was short-circuiting the NuGet resolution I was expecting to take place.
I added a ref from T to A directly and that solved it.

Axiom distribution causes duplicate class issue with AspectJ

Axiom 1.2.15 distribution states in the release notes:
The implementation JARs (axiom-impl and axiom-dom) are now built with AspectJ (to reduce source code duplication) and contain a small subset of classes from the AspectJ runtime library. There is a small risk that this may cause conflicts with other code that uses AspectJ.
Well, this does cause an issue in my project with AspectJ 1.9.2. Maven complains:
09:35:12,617 [WARNING] Found duplicate and different classes in [org.apache.ws.commons.axiom:axiom-dom:1.2.21, org.apache.ws.commons.axiom:axiom-impl:1.2.21, org.aspectj:aspectjrt:1.9.2, org.aspectj:aspectjweaver:1.9.2]:
09:35:12,619 [WARNING] org.aspectj.lang.annotation.Aspect
I can't exclude Axiom from our project as it is being pulled in by Axis. Is there a distribution of Axiom that does not include AspectJ classes or do I need to build one of my own?
This will be fixed in Axiom 1.2.23.

How to solve transitive dependencies version conflicts (scala/sbt)

I have a project with several utility classes. Let's name it Utils.
I have a proj1 which depends on Utils. And another proj2 that depends on proj1 and Utils.
The problem is if both proj1 and proj2 depend on different Utils version this will lead to problems.
What's the best solution?
This situation occurs in Scala/SBT projects, but I guess other languages have the same problems.
Edit:
Just to be clear, proj2 is the project that will run, that uses some code from proj1 and Utils.
This is classic Jar Hell, and it is a problem on any JVM based project not just scala with sbt.
There are 4 common solutions
Get rid of conflict by changing code, consolidate your multiple version dependency into a single dependency.
Shading (as mentioned above by #Sean Viera)
Multiple ClassLoader component architecture like OSGI (as mentioned by #tuxdna)
Run in separate JVMs like a microservice architecture (also mentioned by #tuxdna)
You have three different projects:
Utils
proj1 <- depends on Utils v1
proj2 <- depends on Utils v2
The only way you can be 100% sure that there are no conflicts between proj1 and proj2 is to run them in isolation.
As soon as you will mix proj1 and proj2 with different versions of Utils on the same classpath, you will end up override one or the other project.
You can achive isolation using:
run them in separate JVMs, with appropriate version of Utils
run them in same JVM but in different class loaders

libGDX on SBT: roboVM backend is referencing the wrong ASM version

When trying to compile my Game with roboVM, I keep getting the error:
java.lang.IncompatibleClassChangeError: class org.robovm.compiler.plugin.objc.ObjCProtocolProxyPlugin$1 has interface org.objectweb.asm.ClassVisitor as super class
I have investigated some many hours, coming to the conclusion that it has to do with the ASM library: In the library ASM, up to version 3.3.2, the class ClassVisitor was an interface. It got promoted to an abstract class in 4.0 and the robovm backend bytecode uses a >= 4.0 version while my SBT builder tries to use a version < 4.0.
The roboVM code in question can be found here: https://github.com/robovm/robovm/blob/master/compiler/src/main/java/org/robovm/compiler/plugin/objc/ObjCProtocolProxyPlugin.java#L145
Now, while I realize that this is the issue, I have no idea how to fix / work around it. I do not want to compile libGDX from source...
To setup my app I used existing templates, namely this one: https://github.com/ajhager/libgdx-sbt-project.g8. Also, I use the latest versions respectively:
sbt 0.13.5
libGDX 1.4.1
scala 2.11.3
roboVM 1.0.0-alpha-04
Now when I investigated further, searching for the culprit in this conglomerate, I found that indeed two 'asm's were included in the classpath, the one with version 3.3.1 being mentioned earlier:
scalac -classpath ...:~/.ivy2/cache/asm/asm-all/jars/asm-all-3.3.1.jar:...:~/.ivy2/cache/org.ow2.asm/asm-all/jars/asm-all-4.2.jar:...
This obviously caused the crash. Now I only had to find the place where 3.3.1 was set as dependency and I was rather quick in finding it, at long last: pfn/android-sdk-plugin. For whatever reason, they set this as a dependency (albeit somehow not using it in their code). There were evidently no conflicts since the group ids differed: asm:asm-all:3.3.1 vs org.ow2.asm-all:4.2.
This is easily the dumbest thing I have ever walked across and I'm grinding my teeth that it took so long and so much debugging to get behind it. Hmpf!
I fixed it by cloning the android-sdk-plugin repository and adjusting the ASM version / group id to 4.2. I then continued to sbt publish-local and increased the version number dependency in my project to fit the cloned SNAPSHOT version's.
I hope this will help anyone that stumbles across this behaviour.
So long,
Danyel.