Passing "FileTree" as srcDirs in java closure is not allowed anymore?

Hi all,

I have this issue where I’m trying to create the srcDirs using fileTree. This same code works with gradle plugin 1.5 but with gradle plugin 2.0+, it started giving out the following problem:

Error:Cannot convert the provided notation to a File or URI: directory 'src/A/java'.
The following types/formats are supported:
  - A String or CharSequence path, for example 'src/main/java' or '/usr/include'.
  - A String or CharSequence URI, for example 'file:/usr/include'.
  - A File instance.
  - A URI or URL instance.

Here’s my gradle config snippet:

android {

    buildToolsVersion 23.0.2
    compileSdkVersion 23

    defaultConfig {
        ...
    }

    buildTypes {
        release {
            minifyEnabled true
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            minifyEnabled false
        }
    }

    flavorDimensions(FLAVOR_DIMEN_FEATURES, FLAVOR_DIMEN_ENV)

    productFlavors {
       
        nonprod {
            dimension = FLAVOR_DIMEN_ENV
           ...
        }
        production {
            dimension = FLAVOR_DIMEN_ENV
            ...
        }
        base {
            dimension = FLAVOR_DIMEN_FEATURES
        }
        A {
            dimension = FLAVOR_DIMEN_FEATURES
            minSdkVersion 19
        }
        B {
            dimension = FLAVOR_DIMEN_FEATURES
        }
        aB {
            dimension = FLAVOR_DIMEN_FEATURES
            minSdkVersion 19
        }
    }

    sourceSets {
        .
        .
        .
        .

        aB {
            FileTree treeB = fileTree(dir: 'src/B/java',
                    include: '**/*',
                    excludes: ['**/A*', '**/X*', '**/Z/**'])
            if (treeB != null) {
                treeB.each {File file ->
                    println "treeB - "  + file.getCanonicalPath()
                }
            }
            FileTree treeA = fileTree(dir: 'src/A/java',
                    include: '**/*',
                    excludes: ['**/B*', '**/C*', '**/D/**'])
            if (treeA != null) {
                treeA.each {File file ->
                    println "treeA - "  + file.getCanonicalPath()
                }
            }
            java {
                srcDirs = [treeA,treeB]
            }
            res.srcDirs = ['src/A/res', 'src/B/res']
        }
    }
}

The problem I’m trying to achieve here is combining features “A” and “B” and excluding duplicate classes which are existing in each other.

Please advise the best way to achieve this if the above is not an elegant solution. I was able to get this working in plugin 1.5 but after updating to 2.0 it started failing.

Thanks

You should put the excludes on the sourceDirectorySet itself:

java {
  srcDirs = ['src/A/java', 'src/B/java']
  exclude ['**A/java/**/B*', '**/A/java/**/C*', ...]
}

But the question is: Why do you need these intricate exclude patterns? Couldn’t you put the common files into ‘src/ab/java’ and then include that folder in flavors A, B and aB?

Hi Stefan,

Thanks for your reply. I had tried exactly what you suggested but it doesn’t pick up the path before “java” directory. It still includes the duplicate classes of the two source sets. The package is also exactly the same for the classes which I want to exclude.

Basically, A & B are 2 features of my white-labeled Android App. The main source sets references certain classes such as “AController” and “BController” (and a few dependencies along with it) as entry points for controlling the features A & B.

If A & B are independently built, we don’t have any issues, example (ANonprodDebug or BProductionRelease).

Thus, the purpose of building the product flavor aB is to merge the two features without duplicating the common code. All I need is excluding the BController in A source set and vice versa. Moreover, it is not scalable as well. If I build a feature C which I might want to conditionally include in my source set, I will need to build a new directory “src/abc/java” which may not be feasible… Hope you’re getting where I’m going.

The fileTree approach which I suggested works great in gradle-1.5.0 but not in 2.0.0-betaX.

You’ll have to ask in the Android forum why the filtering is not working on the source set.

Regarding the general design: Why does A contain a BController?

Because the main source set references the corresponding controllers as an entry point.

When we build AProductionDebug, and if we dont have the BController, there would be compile time issues.

Just wondering if you have a better way of doing this :slightly_smiling:

BTW, thanks for your response.

If I understand flavors correctly (I’m no Android dev), then you should be able to have a No-Op BController in your main sourceSet and only overwrite it in the B sourceSet. Then you don’t have any of these filtering issues.