Using local dependencies

I am moving from Ant to Gradle and trying to use some local jars rather than MavenCentral for some private libraries. I am using Kotlin.

In my build.gradle.kts I have:

repositories {
	flatDir {
		name = "libs.dir"
		dirs("libs")
	}
	dependencies {
		 	implementation (files("libs/mrbutil.jar"))
		 	implementation (files("libs/moneydance.jar"))
	}
}

I have displayed the classpath using:

tasks.register("listClass") {
	for (name in sourceSets["main"].runtimeClasspath){
		println(name)
	 }
}

which displays the jars in the classpath:

d:\F\mrbmo\eclipse-workspace\MoneydanceGradle>gradlew listClass
D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\build\classes\java\main
D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\build\resources\main
D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\libs\mrbutil.jar
D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\libs\moneydance.jar
C:\Users\mrbmo\.gradle\caches\modules-2\files-2.1\com.google.guava\guava\32.1.1-jre\ad575652d84153075dd41ec6177ccb15251262b2\guava-32.1.1-jre.jar
C:\Users\mrbmo\.gradle\caches\modules-2\files-2.1\org.jsoup\jsoup\1.11.3\36da09a8f68484523fa2aaa100399d612b247d67\jsoup-1.11.3.jar

When I build the project the classes in the jars are unresolved:

D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\src\main\java\com\moneydance\modules\features\securityquoteload\view\SecurityTableLine.java:216: error: cannot find symbol
        public CurrencyType getBaseCurrency() {
               ^
  symbol:   class CurrencyType
  location: class SecurityTableLine
D:\F\mrbmo\eclipse-workspace\MoneydanceGradle\lib\src\main\java\com\moneydance\modules\features\securityquoteload\view\SecurityTableLine.java:219: error: cannot find symbol
        public void setBaseCurrency(CurrencyType baseCurrency) {
                                    ^
  symbol:   class CurrencyType
  location: class SecurityTableLine

The errors above should not happen as the source compiles correctly with Ant.

Obviously I am missing something. Can anyone give me some pointers please.
Thanks

Let’s start with your listClass task.
It does the “work” during its configuration, not during runtime.
If you would want to do work in the execution phase, you fore example need to wrap it in doLast { ... } or doFirst { ... }.
You currently do the “work” always if the task is configured and during configuration phase, even if the task is not going to be executed.

Then, your flatDir repository is not used at all, you can just remove it.
If the files would be called like foo-1.2.3.jar, then you could do implementation(":foo:1.2.3").
But as your jars have no version number, you can only use files(...) or fileTree(...), so you can just remove the repository.

Also, having dependencies { ... } within repositories { ... } is just visual clutter and decreases readability. It is a top-level setting, so you should move it out.

Regarding the actual error, it is hard to say from the information you provided what might be the problem. Can you maybe provide a build --scan? If not, you might use --info or --debug to get more information about what is happening and with which class paths things get compiled and so on.

Thanks for the quick reply. I have tidied up the build.gradle.kts file:

*
 * This file was generated by the Gradle 'init' task.
 *
 * This generated file contains a sample Java library project to get you started.
 * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.3/userguide/building_java_projects.html in the Gradle documentation.
 */

plugins {
    // Apply the java-library plugin for API and implementation separation.
    `java-library`
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
   }
dependencies {
  	
    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation("com.google.guava:guava:32.1.1-jre")
		       implementation("org.jsoup:jsoup:1.11.3")
		       implementation("com.fasterxml.jackson.core:jackson-core:2.7.4")
		       implementation("com.fasterxml.jackson.core:jackson-databind:2.7.4")
		       implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.7.4")
		       implementation("com.fasterxml.jackson.core:jackson-annotations:2.7.4")   
		       implementation("commons-io:commons-io:2.2")   
		       implementation("org.apache.httpcomponents:httpclient:4.5.6") 	      
		 		implementation (files("libs/mrbutil.jar"))
		 		implementation (files("libs/moneydance.jar"))
}
// Apply a specific Java toolchain to ease working on different environments.
java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(13))
    }
}
tasks.register("listClass") {
	doLast {
		for (name in sourceSets["main"].runtimeClasspath){
			println(name)
		 }
	}
}

and run the --scan. Looking at the scan the only dependencies shown are those from maven. The two local ones are not shown. I ran it with --debug and it showed the two local jars in the compiler arguments so I looked closer at my files. One of the jars had not copied into the libs directory. I have since changed the file entries to fileTree for the libs directory and things have progressed.

Thanks for your time. It was interesting to get first hand experience, the documentation and forum posts sometimes conflict with each other.

1 Like

The buildscan is Build Scan® | Gradle Cloud Services

Maybe local file dependencies are not shown in build scans.
If so, that probably something to report to Gradle.

I agree, it was very confusing. I will look into it once I have completed my migration. There maybe more.

1 Like

Local files that are added to the dependency configuration directly using files(...) circumvent some of the dependency resolution mechanisms and don’t appear in dependency reporting. I’ve always seen a gentle nudge to just always declare dependencies with as many coordinates as possible and treat the flatDir repository as an implementation detail as much as possible rather than just use files(...) because you can. You’re always a little bit more limited with just a local file, but it allows much more of the dependency feature set to work if you end up with a case to use it.

Can you use flatDir if the files are not named with version @jjustinic?
Or would you need to rename the files to make the flatDir work?
And would the flatDir dependencies be shown in a build scan?

Yes, you can use flatDir with or without versions. Your declaration can have a version even if it’s not in the file name. However, if the file name has them, then your declaration must match. This is part of the documented behavior of the flatDir repository type.

To resolve a dependency, this resolver looks for one of the following files. It will return the first match it finds:

  • [artifact]-[version].[ext]
  • [artifact]-[version]-[classifier].[ext]
  • [artifact].[ext]
  • [artifact]-[classifier].[ext]

So, for example, to resolve :junit:junit:4.8.1 , this repository will look for junit-4.8.1.jar and then junit.jar .

The flatDir dependencies will be shown in a build scan, but this isn’t just limited to a build scan. The behavior is the same for the locally generated dependency reporting. It won’t be shown if you just add local files to the configuration. It’s only shown if you resolve coordinates to the local flatDir.

1 Like