Buildship/Eclipse resolves classes differently than Gradle during compilation

buildship

(Clint D) #1

We have a multi-project build. SubprojectA has a monkey-patched-class: org.json.JSONObject (let’s not debate about how bad of an idea this is - we know sadly). SubprojectB refers to SubProjectA - and has a dependency added to a third-party library that ALSO has an org.json.JSONObject.

The problem is that when brought into Eclipse - the class in SubprojectA is being selected for compilation yet Gradle (and STS - how the code was authored) is selecting the dependency’s version of org.json.JSONObject. This causes my eclipse to complain about a compilation issue that gradle (and STS) are not experiencing.

I don’t know how to find the right file to look at the classpath - it’s not in the ‘.classpath’ file apparently. Any help here would be appreciated.

Eclipse Oxygen Release (4.7.0), BuildShip 2.1.2.v20170727-2311-s, java 1.8.0 u131 using Gradle wrapper version = ‘4.0.1’

(I didn’t find an exact match when I searched so forgive me if this is a duplicate question)


(uklance) #2

You might be interested in my monkey-patch plugin which compiles a patch jar by combining a target jar with overridden classes and resources from the module. The module inherits the transitive dependencies from the target jar

You can then use replacedBy to say that the monkey patch replaces json jar similar to how Google collections was replaced by guava

dependencies { 
   modules {      
      module("com.google.collections:google-collections") { 
        replacedBy("com.google.guava:guava")
      } 
   }
}

See “Module replacement rules” here


(Stefan Oehme) #3

The file just shows the raw classpath, have a look at the build path UI in Eclipse.

I’m afraid I’m confused by this. Are you saying that you have a monkey-patch, but you don’t want downstream projects to use the monkey patch?


(Clint D) #4

I understand your confusion. I don’t particularly want or don’t want either class because I think it just ends up complicating matters. What I need is for Buildship to compile the way that STS and Gradle seem to.

I will try to add more clarity. We have probably 10 to 15 subprojects in this one build. Most of them ONLY consume the monkey-patched class. The issue is that one of the projects added a dependency to third-party library: ‘org.json:json:20090211’. When this library is added to the project - for some reason STS and Gradle seem to favor that class over the monkey-patched one yet Buildship favors the monkey-patched one in the subproject. Does that make more sense? The monkey-patched class doesn’t have a constructor that the thirdparty library does (and I can’t "just add it to the monkey-patched class for reasons I can’t get into here).

All our developers will use IntelliJ or Eclipse. The Eclipse users are “stuck” using STS because it works still. I’m trying to make STS and Buildship agree so that I can ask the developers (probably 50-200 people, possibly more) to switch over to using Buildship.

Thank you very much for taking a look at my post!


(uklance) #5

It seems that you have two versions of the class on your classpath and you are therefore relying on classpath ordering which is always a bad idea. If you used my monkey patch plugin there would only be a single version of the class on the classpath so no ordering concerns

Which version of gradle are you using? I seem to remember there was a HashMap used in a previous gradle version instead of a LinkedHashMap in the eclipse classpath generation. This could mean the eclipse classpath ordering is different to gradle’s ordering


(Stefan Oehme) #6

I’m not sure what STS does, but the tooling model that Buildship is querying has (for bettet or worse) two separate sets for project and external dependencies. So we can’t guarantee exactly the same order you’d see in Gradle.

I think the approach that Lance suggests will be the most fruitful. It completely resolves the conflict by making sure you only have your patched jar in all classpaths.