Wednesday, July 13, 2011

Gradle dependencies with jars that have no version number

I have seen presentations and read blogs and articles on Gradle. It sounds pretty good.  Gradle is gathering momentum as some of the major players in the open source community (Hibernate and Spring Security to name a few) have switched their builds over to using Gradle.  I figured it is time to give it a try.

The project I work on is fairly old, pre-Maven I suspect.  The project is a multi-layer, multi-component Java project built using Ant.  The project does not use Maven or Ivy.  The project includes a folder that contains all of our dependent jars. These jars are committed to SVN and included as part of the project when it is checked out. This way we have all the dependencies we need to build the project.  We have quite a few dependent jars that do not have version numbers in the jar name.  Examples include a copy of junit.jar and log4j.jar.  This all existed before I started working on the project, so I have no idea how it got that way - it just is.  And since it's not really broken, we haven't attempted to fix it!

Not having version numbers in the jars is a minor inconvienence.  If you read the Gradle User Guide chapter on Dependency Management, they seems to push dependency management for jars with version numbers.  Most of the examples shown in the documentation and elsewhere declare the dependencies as seen in Example 34.1 in Dependency Management chapter.  Great, but what do I do if I don't have version numbered jars in my dependencies?  I did not believe the Gradle guys would leave me hanging...  And they didn't!

I really wanted to figure out how to setup my classpath to include these jars without version numbers.  I figured out how to do this and started writing this blog.   Then as I re-read the Dependency Management chapter, I saw a clue that I must have blown right by the first time I read it.  The clue is in Section 34.3.5 File dependencies.  You can use the FileTree  to help define the classpath to include these non-versioned jars.

I created a small project called GradleTest that did not use the standard Java plugin conventions for the source and resource files and has dependencies in the "libs" folder, none of which have version numbers in the jar names.



I created two different options, which both seem to work.  The first is shown below.  This option handles the dependencies more specifically, assigning just the jars that are needed for either compile or runtime.

apply plugin: 'java'

sourceCompatibility = 1.6
version = '1.0'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'resources'
        }
        compileClasspath += fileTree(dir: './libs', includes: ['**/log4j.jar'])
        runtimeClasspath = classes + sourceSets.main.classes + fileTree(dir: './libs', includes: ['**/log4j.jar'])
        
    }
    test {
        java {
            srcDir 'test'
        }
        resources {
            srcDir 'testresources'
        }
        compileClasspath += fileTree(dir: './libs', includes: ['**/junit.jar'])
        runtimeClasspath += classes + fileTree(dir: './libs', includes: ['**/junit.jar', '**/log4j.jar']) 
        
    }
}

sourceSets.main.classesDir = new File("./build/classes")
sourceSets.test.classesDir = new File("./build/classes")

The second option looks very similiar to the first option,  but uses the dependencies definition and it cheats by assigning all the jars in the "libs" folder to both the compile and runtime classpath, rather than just exactly what is needed.


apply plugin: 'java'

sourceCompatibility = 1.6
version = '1.0'

sourceSets {
    main {
        java {
            srcDir 'src'
        }
        resources {
            srcDir 'resources'
        }
        
    }
    test {
        java {
            srcDir 'test'
        }
        resources {
            srcDir 'testresources'
        }
        
    }
}

sourceSets.main.classesDir = new File("./build/classes")
sourceSets.test.classesDir = new File("./build/classes")

configurations {
    compile {
        description = 'compile classpath'
        transitive = true
    }
    runtime {
        extendsFrom compile
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')

}

I am sure there are other,  possibly better or cleaner alternatives.  Please feel free to share improvements or other alternatives.   Hope this helps....

1 comment:

  1. YOu can use the flatDir repository type to fully integrate non-versioned jars stored in a file system with default Gradle dependency management. The following Gradle code pulls log4j from the public Maven repository, and "somelib.jar" from a local file server:

    repositories {
    mavenCentral()
    flatDir name: 'nas', dirs: '//MyWindowsServer/mylibs'
    }

    dependencies {
    compile group: 'log4j', name: 'log4j', version: '1.2.8'
    compile name: 'somelib'
    }


    One note: in current stable versions of Gradle, this will break the eclipse plugin unless you add:

    eclipseClasspath.downloadSources = false

    ReplyDelete