Hi,
I have a multiproject build, with GradleProject depending on GradleBase.
GradleBase depends on some libraries, e.g. commons-configuration.
Suppose I need to hack a class in commons-configuration: I can copy the source code from that class and paste on project GradleBase. Everything works fine when running from GradleBase.
The problem arises when I use that class from GradleProject: in the eclipse classpath the GradleBase dependency is always at the bottom of the list:
So the original class from commons-collection is loaded and my code in never executed.
Is there a way to put the project dependency on top of the list?
I tried something like this, to reorder the entries in classpath, but the order is always the same:
Perhaps you could approach this another way and instead tweak the jar to remove the offending class file. Then you wouldn’t need to rely on classpath ordering.
I understand your approach, but I would prefer to be able to shadow a class without going into this kind of pre-compile-packaging; as I understand, I would need to list every file I want to shadow in build.gradle. I think this is not very straight forward as simple classpath ordering.
I think that since classpath ordering is an issue in Java (using gradle or not), Gradle should provide a way to manage it. I understand that runtime class shadowing and classpath ordering is not good programming technique and may lead to obscure errors, but that is Java (at least Java 8)!
Not necessarily… You could write a filter that includes every class file that doesn’t have a corresponding java file in your project
Considering commons config is open source, another approach would be to download the sources from maven central and compile a new jar with your overridden classes
Or better yet, if it’s a bug you’re fixing… Contribute the fix to commons config
Wow! Gradle is indeed powerful! Would you figure me out some idea about how to do that?
Still, I think the build script becomes quickly complicated adding such things… classpath ordering would still be better… but, wait… is it possible to do classpath ordering in gradle?
There is no way to reorder them, because project and external dependencies are handled as two distinct buckets in the Tooling API. But I agree projects should come first so we can support this use case. @donat do you think this is something we can fit into 2.0.1?
I did a quick check and I have some bad news. It seem that the change breaks the fix we did for https://bugs.eclipse.org/bugs/show_bug.cgi?id=473348 Fortunately only projects with older Gradle versions (2.5-) are affected.
Besides, there’s another problem. Even if I change the classpath ordering, it is not reflected in the package explorer view. In other words, projects under the “Project and External Dependencies” node are placed after the libraries even if they come before in the project’s classpath. This will likely confuse other users.
This would be very confusing! Unfortunately, I have not enough knowledge to help you… I still think that classpath ordering, since it is possible in java, should be possible in gradle/buildship too… see what you can do…
It’s a java se application (I wrote frontend without being too precise…).
I mean it is not a library but the final app deployed to the customer, so no one else will use that.
I mean it is not a library but the final app deployed to the customer
You’ll need to ensure that the app startup script has the exact same classpath ordering as your eclipse classpath. Whilst doable I still feel this is hacky considering there’s the option to remove the duplicates from the classpath
Ok, but while removing the duplicates from the classpath, you are imposing ordering too! Infact, excluding some class from a jar because I have a copy of that in my project, means that my project “comes first” the library… offcourse, you are doing that at compile time instead of runtime, which is generally better.
But, consider that in my use case I package all of my classes in a single jar that has the entry point of the application (main method); I create a Class-Path manifest entry (at build time) on the main jar, linking to all needed libraries, so the launch script is simply “java -cp myjar.jar com.company.MainClass”. This way, I don’t have to care about ordering both at compile time and at runtime. The real problem is within Eclipse during debug…
Would this be true for composite builds? ie would the classpath ordering change when a project is included in a composite? Because that sounds like a bad idea to me
removing the duplicates from the classpath, you are imposing ordering too
By removing the duplicates it means consumers don’t need to concern themselves with ordering. One consumer is eclipse, the other is the app startup script. Unit tests and integration tests could also be considered as consumers.
With your approach you’ll need to ensure every consumer has the right path ordering, this will likely require duplication of sorting logic across eclipse, junit and your startup script.