Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle + AndroidAnnotations generates duplicate class errors - need to clean project before every build

I have a problem with migrating my IntelliJ IDEA project to Android Studio using a gradle build. I have set up the AndroidAnnotations library like recommended in various other posts, and it works just fine. But, when compiling my project multiple times without executing the :clean task in between, I get following error messages:

/project-dir/build/source/apt_generated/flavor1/release/com/example/app/MyActivity_.java:15: error: duplicate class: com.example.app.MyActivity_

[more errors here...]

I believe that multiple builds in series fail because AndroidAnnotations re-creates the *_.java files always before the :compile tasks (without checking whether it is necessary or not) and the :compile task recognizes the new files (e.g using timestamp) but already finds those as pre-compiled *.class files, thus throwing the error. Is this possible? How can I prevent this behavior? Can I add a necessity-check for AndroidAnnotations? Or is this some other problem?


UPDATE 1: It seems that the error is thrown from AndroidAnnotations itself, since :compile works when I delete the *.java files inside the apt_generated folder manually.


UPDATE 2:

I removed following line from my build.gradle:

// Automatically add the generated source code to the source set
android.sourceSets[getSourceSetName(variant)].java.srcDirs += aptOutput

I don't exactly know why it works without this line. Since I did not add the folder using Android Studio's Mark Directory as > Sources Root. Probably this is some result of caching? Or does gradle somehow add my generated java files automatically to the classpath?

I would be thankful for any comments nonetheless.


UPDATE 3 / SOLUTION

After removing the line and synchronizing the gradle build file with Android Studio, the auto-generated source code was removed as Source Root, causing the IDE to show errors of missing classes.

Eventually, I found the solution on the Android Annotations github issues: https://github.com/excilys/androidannotations/issues/676

I re-added the statement for adding it to the source sets (allowing Android Studio to show it as source root). Furthermore, I removed the files from the variants source collection using this:

variant.javaCompile.source = variant.javaCompile.source.filter { p ->
    return !p.getPath().startsWith(aptOutputDir.getPath())
}

Now the generated files are recognized, and the duplicate class error is gone.

Best regards, David

Here is my final build.gradle. I hope this helps some of you:

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

apply plugin: 'android'

repositories {
    mavenCentral()
}

configurations {
    // This is the annotations processor dependency configuration.
    apt
}

def getSourceSetName(variant) {
    return new File(variant.dirName).getName();
}

android {
    compileSdkVersion 18

    defaultConfig {
        versionCode 10
        versionName "1.0.2"
        targetSdkVersion 17
        minSdkVersion 10
    }

    buildToolsVersion "18.0.1"

    buildTypes {
        release {
            zipAlign true
        }
    }

    productFlavors {
        flavor1 {}
        flavor2 {}
    }

    // This has to go after the productFlavors command (otherwise moving the flavor source set root fails).
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        // We move the root of our flavors to support our legacy structure.
        flavor1.setRoot('flavors/flavor1')
        flavor2.setRoot('flavors/flavor2')
    }

    applicationVariants.all { variant ->
        def aptOutputDir = project.file("${project.buildDir}/source/apt_generated")
        def aptOutput = new File(aptOutputDir, variant.dirName)

        println "****************************"
        println "variant: ${variant.name}"
        println "manifest:  ${variant.processResources.manifestFile}"
        println "aptOutput:  ${aptOutput}"
        println "****************************"

        android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()

        variant.javaCompile.doFirst {
            println "*** Running AndroidAnnotations for ${variant.name}"
            aptOutput.mkdirs()


            variant.javaCompile.options.compilerArgs += [
                    '-processorpath', configurations.apt.getAsPath(),
                    '-AandroidManifestFile=' + variant.processResources.manifestFile,
                    '-s', aptOutput
            ]
        }

        variant.javaCompile.source = variant.javaCompile.source.filter { p ->
            return !p.getPath().startsWith(aptOutputDir.getPath())
        }
}

dependencies {
    // Android-Annotations
    apt 'com.googlecode.androidannotations:androidannotations:2.7.1'
    compile 'com.googlecode.androidannotations:androidannotations-api:2.7.1'

    // Include libraries only in flavor1
    flavor1Compile fileTree(dir: 'libs', include: '*.jar')
}

Here is my (initial) build.gradle (I stripped of non relevant parts):

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

apply plugin: 'android'

repositories {
    mavenCentral()
}

configurations {
    // This is the annotations processor dependency configuration.
    apt
}

def getSourceSetName(variant) {
    return new File(variant.dirName).getName();
}

android {
    compileSdkVersion 18

    defaultConfig {
        versionCode 10
        versionName "1.0.2"
        targetSdkVersion 17
        minSdkVersion 10
    }

    buildToolsVersion "18.0.1"

    buildTypes {
        release {
            zipAlign true
        }
    }

    productFlavors {
        flavor1 {}
    }

    // This has to go after the productFlavors command (otherwise moving the flavor source set root fails).
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        // We move the root of our flavor to support our legacy structure.
        flavor1.setRoot('flavors/flavor1')
    }

    applicationVariants.all { variant ->
        aptOutput = file("${project.buildDir}/source/apt_generated/${variant.dirName}")
        println "****************************"
        println "variant: ${variant.name}"
        println "manifest:  ${variant.processResources.manifestFile}"
        println "aptOutput:  ${aptOutput}"
        println "****************************"

        // Automatically add the generated source code to the source set
        android.sourceSets[getSourceSetName(variant)].java.srcDirs += aptOutput

        variant.javaCompile.doFirst {
            println "*** Running AndroidAnnotations for ${variant.name}"
            aptOutput.mkdirs()

            variant.javaCompile.options.compilerArgs += [
                    '-processorpath', configurations.apt.getAsPath(),
                    '-AandroidManifestFile=' + variant.processResources.manifestFile,
                    '-s', aptOutput
            ]
        }
    }
}

dependencies {
    // Android-Annotations
    apt 'com.googlecode.androidannotations:androidannotations:2.7.1'
    compile 'com.googlecode.androidannotations:androidannotations-api:2.7.1'

    // Include libraries only in flavor1
    flavor1Compile fileTree(dir: 'libs', include: '*.jar')
}

I would appreciate any help.

Thanks, David

like image 832
david.schreiber Avatar asked Nov 11 '22 21:11

david.schreiber


1 Answers

If you export the build.gradle from Eclipse, it includes .apt_generated in the gradle file and it shouldn't. Take this out and these errors should go away.

like image 146
kenyee Avatar answered Nov 14 '22 23:11

kenyee