Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I force the order of dependencies in my classpath with Gradle?

A project runs on Google App Engine. The project has dependency that uses a class that can't be invoked on App Engine due to security constraints (it's not on the whitelist). My (very hacky) solution was to just copy a modified version of that class into my project (matching the original Class's name and package) that doesn't need the restricted class. This works on both dev and live, I assume because my source appears in the classpath before my external dependencies.

To make it a bit cleaner, I decided to put my modified version of that class into it's own project that can be packaged up in a jar and published for anyone else to use should they face this problem.

Here's my build.gradle:

// my jar that has 'fixed' version of Class.
compile files('path/to/my-hack-0.0.1.jar')

// dependency that includes class that won't run on appengine
compile 'org.elasticsearch:elasticsearch:1.4.4'

On my local dev server, this works fine, the code finds my hacked version of the class first at runtime. On live, for some unknown reason, the version in the elasticsearch dependency is loaded first.

I know having two versions of the same class in the classpath isn't ideal but I was hoping I could reliably force my version to be at the start of the classpath. Any ideas? Alternatively, is there a better way to solve this problem?

like image 505
matt burns Avatar asked Jul 29 '15 10:07

matt burns


People also ask

Does the order of dependencies matter in Gradle?

This isn't necessary. The order inside the dependencies { } block is preserved. You are kind of right. Dependency ordering is preserved, but for example all compile dependencies will be before testCompile dependencies no matter of how you order them.

How do I force Gradle to refresh dependencies?

Simply open the gradle tab (can be located on the right) and right-click on the parent in the list (should be called "Android"), then select "Refresh dependencies". This should resolve your issue.

What is classpath in Gradle?

Gradle dependencies are grouped into sets called configurations. Different configurations are used for building classpath for the major two tasks — compile classpath is used for compilation and runtime classpath is used for running the application.

How does Gradle resolve transitive dependencies?

Releases of a module hosted on a repository can provide metadata to declare those transitive dependencies. By default, Gradle resolves transitive dependencies automatically. The version selection for transitive dependencies can be influenced by declaring dependency constraints.


1 Answers

Not really sure if this is what people visiting this question were looking for, but this was what my problem and a solution that I reached at. Jar A: contains class XYZ Jar B: also contains class XYZ My Project needs Jar B on the classpath before Jar A to be able to get compiled.

Problem is Gradle sorts the dependencies based on alphabetical order post resolving them which meant Jar B will be coming after Jar A in the generated classpath leading to error while compiling.

Solution: Declare a custom configuration and patch the compileClasspath. This is how the relevant portion of build.gradle might look like.

configurations {
    priority
    sourceSets.main.compileClasspath = configurations.priority + sourceSets.main.compileClasspath
}

dependencies {
    priority 'org.blah:JarB:2.3'
    compile 'org.blah:JarA:2.4'
    ...
}
like image 101
6harat Avatar answered Sep 26 '22 05:09

6harat