Eric Wu
Eric Wu

Reputation: 452

Gradle: common resource dependency for multiple java projects

I'm developing a multi-module project with gradle/intellij-idea, and here is the structure of my project home:

project/
  sub-project-1
    /main/resources
  sub-project-2
    /main/resources
  data
    /main/resources
    /test/resources

As you can see I have multiple sub-projects (all java), how can I make them depend on some common resources (the "data" project, which contains no code but only resources), as well as their own separate resources?

Also it's best that the intellij-idea can pick up these dependencies with JetGradle automatically (JetGradle do just fine picking up the default gradle java project dependencies within each sub project).

Thanks a lot!

Upvotes: 26

Views: 24568

Answers (8)

Michał Krzywański
Michał Krzywański

Reputation: 16910

If all your projects are java projects and you apply java plugin to them you can just do the following. Assuming your directory structure you could do :

def dataMainResourcesPath = rootProject.projectDir.path + '/data/main/resources'
def dataTestResourcesPath = rootProject.projectDir.path + '/data/test/resources'

subprojects.each {
    it.sourceSets.main.resources.srcDirs += dataMainResourcesPath
    it.sourceSets.test.resources.srcDirs += dataTestResourcesPath
}

in your root build.gradle.

Upvotes: 0

Tono Wiedermann
Tono Wiedermann

Reputation: 608

The approach I took was to use project reference

sourceSets {
    main {
        resources {
            srcDirs += [
                project(':data').sourceSets.main.resources
            ]
        }
    }
}

UPDATE: Tested with Gradle7 and it still works. Tested with java-library plugin.

Upvotes: 21

Vladimir
Vladimir

Reputation: 555

I had another problem with resources in multi-module project, may be it will helpful for somebody.

I have two independent modules:

- database (contains migrations for whole project)
- main (contains business logic(controllers, services and etc))

Also I use Spring-Boot 2 in my project.

I have integration tests in main and before test is started I need to create schema and tables in DB. But all my migrations (use Flyway for migration control) in database module. Path for migration is src/main/resources/db/migrations.

As a result I need to have all migrations in /test/resources in order to start tests. Of course, I don't want to duplicate migrations in main module and I found this solution. I need to add these lines in files in main module.

builde.gradle

dependencies { 
   testImplementation "com.example.module:database:$dbMigrationVersion"
}

application-test.yml

spring:
  flyway:
     locations: classpath:/BOOT-INF/classes/db/migration

After these lines all your migrations from  database module will be in main module classpath (in our case for test profile). And flyway can execute them before starting tests.

Upvotes: 0

Nelson
Nelson

Reputation: 323

sourceSets {
    main {
        resources {
            srcDirs += [
                '../sub-project-1/src/main/resources',
                '../sub-project-2/src/main/resources',
                '../data/src/main/resources'
            ]
        }
    }

    test {
        resources {
            srcDir '../data/src/test/resources'
        }
    }    
}

Upvotes: 0

Peter Niederwieser
Peter Niederwieser

Reputation: 123900

One solution is to apply the Java plugin also to the data project, and then use regular project dependencies (e.g. dependencies { runtime project(":data") }). However, this would require a bit of effort to prevent shipping the test resources.

Another solution is not to make data a Gradle project but literally include its resource directories in the other two projects (sourceSets.main.resources.srcDir "../data/main/resources"; sourceSets.test.resources.srcDir "../data/test/resources").

Upvotes: 14

Dmitri Korobtsov
Dmitri Korobtsov

Reputation: 417

And here is version for Kotlin DSL - to sync all resources from :data module to root and all sub-modules build/resources folders:

// Synchronizing resources from :data module to project root: build/resources
synchronizeSharedResources()

subprojects {
    // Synchronizing resources from :data module to all submodules: build/resources
    synchronizeSharedResources()
}

fun Project.synchronizeSharedResources() {
    sourceSets {
        main {
            resources.srcDir(project(":data").sourceSets["main"].resources.srcDirs)
        }
        test {
            resources.srcDir(project(":data").sourceSets["test"].resources.srcDirs)
        }
    }
}

Upvotes: 3

nucatus
nucatus

Reputation: 2296

You need to choose the project which will hold your resources. All the other projects that require those resources, will add them to the resources component of the sourceSets.

sourceSets {
    data {
        resources {
            srcDir "${project(':data').projectDir}/src/main/resources"
            include "your_pattern_here**"
        }
    }
    main {
        resources {
            srcDirs += [ data.resources ]
        }
    }
}

Upvotes: 6

Eric Wu
Eric Wu

Reputation: 452

Ok, I figured it out. It's actually pretty simple. Just treat the "data" folder as another project and add dependency declarations to sub projects will do the trick. For example:

dependencies {
    compile project (':data')
    testCompile project (':data')
}

Upvotes: 4

Related Questions