1

I am using the Parceler library on Android (https://github.com/johncarl81/parceler)

And I am also using Jacoco for code coverage.

However after adding Parceler running my test code coverage with Jacoco now fails with the following error:

Caused by: java.io.FileNotFoundException: /Users/me/android/myapp/blah/app/build/intermediates/classes/demo/com/me/blah/appname/model/User$Parcelable$Creator$0.class (No such file or directory)

The User class is as follows:

@Parcel
public class User {

    @SerializedName("firstName")
    String firstName;

    @SerializedName("lastName")
    String lastName;

    @SerializedName("profileImage")
    ProfileImage profileImage;

    @SerializedName("username")
    String username;

    // empty constructor needed by the Parceler library
    public User() {
    }

}

And my Jacoco file is like this:

apply plugin: 'jacoco'

android {
    testOptions {
        unitTests.all {
            jacoco {
                includeNoLocationClasses = true
            }
        }
    }
}

project.afterEvaluate {

    android.applicationVariants.all { variant ->
        def name = variant.name
        def testTaskName = "test${name.capitalize()}UnitTest"

        tasks.create(name: "${testTaskName}Coverage", type: JacocoReport, dependsOn: "$testTaskName") {
            group = "Reporting"
            description = "Generate Jacoco coverage reports for the ${name.capitalize()} build."

            classDirectories = fileTree(
                    dir: "${project.buildDir}/intermediates/classes/${name}",
                    excludes: ['**/R.class',
                               '**/R$*.class',
                               '**/*$ViewInjector*.*',
                               '**/*$ViewBinder*.*',
                               '**/BuildConfig.*',
                               '**/Manifest*.*',
                               '**/*$ViewBinder*.*',
                               '**/*$ViewInjector*.*',
                               '**/Lambda$*.class',
                               '**/Lambda.class',
                               '**/*Lambda.class',
                               '**/*Lambda*.class',
                               '**/*InjectAdapter*.*',
                               '**/*StaticInjection*.*',
                               '**/*ModuleAdapter*.*']
            )

            sourceDirectories = files(['src/main/java'].plus(android.sourceSets[name].java.srcDirs))
            executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")

            reports {
                xml.enabled = true
                html.enabled = true
            }
        }
    }
}

I am wondering do I need to add the generated Parceler files to the excludes list in my Jacoco file? If so how do I do that? I have tried various variations but none seem to work.

The error complains that the following file is missing:

User$Parcelable$Creator$0.class

Which it is and instead the file is generated as follows:

User$$Parcelable.class

Can anyone explain this?

Donal Rafferty
  • 19,707
  • 39
  • 114
  • 191

2 Answers2

2

I just exclude it in jacocoAndroidCoverage.gradle, like this and it works now

def coverageSourceDirs = [
        '../app/src/main/java'
]

task jacocoStagingDebugCoverageReport(type:JacocoReport, dependsOn: ["connectedStagingDebugAndroidTest"]) {
    group = "Reporting"

    description = "Generate Jacoco coverage reports for staging debug"
    classDirectories = fileTree(
            dir: '../app/build/intermediates/classes/staging/debug/com/',
            excludes: ['**/R.class',
                       '**/R$*.class',
                       '**/*$ViewInjector*.*',
                       '**/*$ViewBinder*.*',
                       '**/*MembersInjector*.*',
                       '**/BuildConfig.*',
                       '**/Manifest*.*',
                       '**/*$Lambda$*.class',
                       '**/*Factory*.class',
                       '**/*$Builder*', 
                       '**/*$Parcelable*.*',
                       '**/*DaggerApplicationComponent*.class',
                       '**/api']
    )

    additionalSourceDirs = files(coverageSourceDirs)
    sourceDirectories = files(coverageSourceDirs)
    executionData = files('build/outputs/code-coverage/connected/flavors/staging/coverage.ec')

    reports {
        xml.enabled = true
        html.enabled = true
    }
}
Ihor Bykov
  • 1,843
  • 3
  • 15
  • 22
1

Try this:

jacocoAndroidUnitTestReport {
    excludes += ['**/*Creator.class']
}

Dr.jacky
  • 3,341
  • 6
  • 53
  • 91
  • I used a variation of this: `excludes += ['**/*\$Creator.class']` This will exclude `Creator` inner classes, but not any `MyFooCreator` real class you have in your project. – Carmen May 26 '20 at 11:15
  • @Carmen I guess you need to remove `\$`. That star before `Creator` should cover `MyFoo`. No? If didn't work, change it to `**/*$Creator.class` – Dr.jacky May 26 '20 at 11:34