sockeqwe / fragmentargs

Annotation Processor for setting arguments in android fragments
http://hannesdorfmann.com/android/fragmentargs
Apache License 2.0
1.08k stars 87 forks source link

Unable to build project, despite the *Builder classes are generated #50

Closed thekalinga closed 8 years ago

thekalinga commented 8 years ago

I have this strange issue which I am facing recently. In Android Studio, after I build, I see that there are no compilation errors within the code (Builder classes are available), but the build for some reason fails saying Builder classes are missing. The build fails to run both from IDE & terminal.

<root>/build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.0-alpha1'
    }
}

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }
        maven { url "https://clojars.org/repo/" }
    }
}

app/build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.3.0-beta4'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        classpath 'com.google.gms:google-services:2.1.0-alpha1'
    }
}

apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'com.google.gms.google-services'

ext {
    daggerVersion = '2.0.2'
    androidSupportLibsVersion = '23.2.1'
    okhttpVersion = '2.6.0'
    icepickVersion = '3.1.0'
    fragmentargsVersion = '3.0.2'
    parcelablepleaseVersion = '1.0.1'
    leakCanaryVersion = '1.3.1'
    dbflowVersion = '3.0.0-beta5'
    playServicesVersion = '8.3.0'
}

android {
    compileSdkVersion 23
    buildToolsVersion '23.0.2'
    defaultConfig {
        applicationId "com.lc"
        minSdkVersion 16
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
        multiDexEnabled true
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    buildTypes {
//        debug {
//            debuggable true
//            minifyEnabled false
//        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        offline {
            debuggable true
            applicationIdSuffix '.offline'
            signingConfig signingConfigs.debug
            minifyEnabled false
            lintOptions {
                checkReleaseBuilds false
                // Or, if you prefer, you can continue to check for errors in release builds,
                // but continue the build even when errors are found:
                abortOnError false
            }
        }
    }

    dexOptions {
        preDexLibraries true
//        incremental true
        javaMaxHeapSize "2g"
    }

    packagingOptions {
        exclude 'LICENSE.txt'
    }

    productFlavors {
        dev {
            minSdkVersion 21 // For improving performance of builds
        }
        prod {} // This should be the published version
    }

}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')

    // DI
    apt 'com.google.dagger:dagger-compiler:' + daggerVersion
    compile 'com.google.dagger:dagger:' + daggerVersion
    compile 'javax.annotation:javax.annotation-api:1.2'

    // Rest
    compile 'com.squareup.retrofit:retrofit:1.9.0'
    offlineCompile 'com.squareup.retrofit:retrofit-mock:1.9.0'
    compile 'com.squareup.okhttp:okhttp:' + okhttpVersion
    compile 'com.squareup.okhttp:okhttp-urlconnection:' + okhttpVersion
    compile 'com.google.code.gson:gson:2.5'

    // Handy utils
    compile 'com.hannesdorfmann.mosby:mvp:2.0.0'
    compile 'com.hannesdorfmann.mosby:viewstate:2.0.0'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'frankiesardo:icepick:' + icepickVersion
    apt 'frankiesardo:icepick-processor:' + icepickVersion
    compile 'com.hannesdorfmann.fragmentargs:annotation:' + fragmentargsVersion
    apt 'com.hannesdorfmann.fragmentargs:processor:' + fragmentargsVersion
    compile 'com.hannesdorfmann.parcelableplease:annotation:' + parcelablepleaseVersion
    apt 'com.hannesdorfmann.parcelableplease:processor:' + parcelablepleaseVersion

    // Async communication
    compile 'io.reactivex:rxjava:1.0.16'
    compile 'com.artemzin.rxjava:proguard-rules:1.0.16.2'
    compile 'io.reactivex:rxandroid:1.0.1'
//    compile 'com.squareup:otto:1.3.8'

    // Support libs
    compile 'com.android.support:support-v4:' + androidSupportLibsVersion
    compile 'com.android.support:design:' + androidSupportLibsVersion
    compile 'com.android.support:palette-v7:' + androidSupportLibsVersion
    compile 'com.android.support:cardview-v7:' + androidSupportLibsVersion
    compile 'com.android.support:recyclerview-v7:' + androidSupportLibsVersion
    compile 'com.android.support:appcompat-v7:' + androidSupportLibsVersion
    compile 'com.android.support:support-annotations:' + androidSupportLibsVersion
    compile 'com.android.support:multidex:1.0.0'

    compile 'com.google.android.gms:play-services-gcm:' + playServicesVersion
    compile 'com.google.android.gms:play-services-location:' + playServicesVersion
    compile 'com.google.android.gms:play-services-maps:' + playServicesVersion

//    compile ('com.google.android.gms:play-services:7.5.0') {
//        exclude module:'play-services-plus'
//        exclude module:'play-services-wallet'
//        exclude module:'play-services-wearable'
//        exclude module:'play-services-panorama'
//        exclude module:'play-services-games'
//        exclude module:'play-services-fitness'
//        exclude module:'play-services-drive'
//        exclude module:'play-services-ads'
//    }

    // Sqllite orm
    apt "com.github.Raizlabs.DBFlow:dbflow-processor:${dbflowVersion}"
    compile "com.github.Raizlabs.DBFlow:dbflow-core:${dbflowVersion}"
    compile "com.github.Raizlabs.DBFlow:dbflow:${dbflowVersion}"

    // Font
    compile 'uk.co.chrisjenx:calligraphy:2.1.0'
    compile 'com.mikepenz:iconics-core:2.5.9@aar'
    compile 'com.mikepenz:google-material-typeface:2.2.0.1.original@aar'
    compile 'com.mikepenz:fontawesome-typeface:4.5.0.1@aar'

    // Java 8
    compile 'net.sourceforge.streamsupport:streamsupport:1.4.1'

    // Misc
    provided 'org.projectlombok:lombok:1.16.6'
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.jakewharton.timber:timber:4.1.0'
    compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar'

    debugCompile 'com.squareup.leakcanary:leakcanary-android:' + leakCanaryVersion
    offlineCompile 'com.squareup.leakcanary:leakcanary-android:' + leakCanaryVersion
    releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:' + leakCanaryVersion

    provided 'com.google.code.findbugs:annotations:3.0.1'

    // UI Testing
    androidTestApt 'com.google.dagger:dagger-compiler:2.0.2'
    androidTestCompile 'com.android.support.test:runner:0.3'
    androidTestCompile 'com.android.support.test:rules:0.3'
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
    androidTestCompile 'junit:junit:4.12'
    androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.5.3'
}

retrolambda {
    jdk System.getenv("JAVA_HOME")
    oldJdk System.getenv("JAVA5_HOME")
    javaVersion JavaVersion.VERSION_1_5
//    jvmArgs '-noverify'
}

configurations.all {
    resolutionStrategy.force 'com.android.support:support-annotations:' + androidSupportLibsVersion
}

android {
    packagingOptions {
        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
}

One of the error is Error:(8, 37) error: cannot find symbol class ItemFragmentBuilder

Can you please let me know what could be causing the issue.

sockeqwe commented 8 years ago

Are there more errors? I think this error has been caused by a compile error which is not caused by FragementArgs. Can you post the whole error log?

thekalinga commented 8 years ago

Please find the debug log for ./gradlew clean assemble --debug debug.txt

sockeqwe commented 8 years ago

Could this be the source of your error?

home/thekalinga/dev/idealx/lc-android/app/src/main/java/com/lc/storage/DatabaseServiceImpl.java:5: error: cannot find symbol
02:27:02.721 [ERROR] [system.err] import com.lc.storage.model.Location_Table;
thekalinga commented 8 years ago

Hi,

This class is also present in the generated source. Lemme comment that part and post the result here

Thanks

sockeqwe commented 8 years ago

From my point of view the problem is as follows: Gradle will try to compile all your classes. If there was a compilation error (not caused by FragmentArgs) then gradle will output this error which that seems to be the case here:

home/thekalinga/dev/idealx/lc-android/app/src/main/java/com/lc/storage/DatabaseServiceImpl.java:5: error: cannot find symbol
02:27:02.721 [ERROR] [system.err] import com.lc.storage.model.Location_Table;

As already said, gradle will also compile all other classes (gradle doesn't stop just because of one compilation error). However, since annotation processing didn't started because of an other compilation error the FragmentArgs Builder classes are not generated and gradle will output this "error message" as well (Builder not found). But the real problem is the other compilation error that has caused annotation processing to not be start.

thekalinga commented 8 years ago

Thanks for your prompt response.

I have commented out the other code and ran the build again. I still have the same error with this time only errors from FragmentArgs.

Please find the latest debug.txt in the attachment.

PS: Please note that even the other class is generated at the build time (I am not sure if there are any issues with the version of gradle plugin I'm using).

debug.txt

sockeqwe commented 8 years ago

Do you use gradle's incremental build feature? This will break annotation processing: https://github.com/google/dagger/issues/298

From the debuglog I can't find anything wrong, but there is too much text, I might have overlooked something.

Try the following: Open android studio. Then do in main menu Build -> rebuild project . Then there should be error messages (the same as in debug.txt), but now you can click on each of them. Please click on every single one, step by step, to jump to the position in your source codeand check if the builder is missing or if something else has caused the error.

My hope is still that you will find another compilation error (not caused by FragmentArgs).

thekalinga commented 8 years ago

I have disabled InstantRun in the IDE & incremental builds in the gradle script

    dexOptions {
        preDexLibraries true
//        incremental true
        javaMaxHeapSize "2g"
    }

I even tried disabling preDexLibraries. Still no luck.

I used fix the issues the same way you specified, whenever I see compilation error from fragmentargs. But for some strange reason, I ran out of all other compilation errors (other than *Builder ones).

I'll go over all the compilation errors again and see if I have missed anything.

Thanks for your response again. I'll post an update here once I find a reason/stuck against a wall. I dont see any clue in the log which specifies the root cause of the error.

thekalinga commented 8 years ago

I use dagger 2 & the compiler for some reason does not complain that generated dagger files (Dagger*Component) are not available. I believe dagger must be using a different mechanism than fragmentargs

thekalinga commented 8 years ago

Ran thru everything again. All the errors are related Builder. However, I see all the *Builder files generated in `/app/build/generated/source/apt/dev/debug/com/*/fragment` directories.

Is there a way for me to debug this thing to see when the source is generated & debug the build flow exactly at the final compilation point

sockeqwe commented 8 years ago

Pretty strange. Cleaning the project doesn't help, right? Unfortunately there is no way to hook in easily in annotation procssing. What have you changed since last time compilation was successful?

Ashok Koyi notifications@github.com schrieb am Di., 15. März 2016 um 23:02 Uhr:

Ran thru everything again. All the errors are related Builder. However, I see all the *Builder files generated in `/app/build/generated/source/apt/dev/debug/com/*/fragment` directories.

Is there a way for me to debug this thing to see when the source is generated & pause the debug flow exactly at the final compilation point

— You are receiving this because you modified the open/close state.

Reply to this email directly or view it on GitHub https://github.com/sockeqwe/fragmentargs/issues/50#issuecomment-197045145

thekalinga commented 8 years ago

Various things.

  1. Added google services plugin
  2. Updated support library
  3. Upgraded build plugin
  4. A lot more code changes (>30+ new classes for various additional flows)

I'll revert the complete code to the previous version and do incremental changes from that version to this & see what might be causing the issue.

Yes.. I have clean & build multiple times. Its not of much use. I'll post an update tomorrow on this.

Thanks for your response.

sockeqwe commented 8 years ago

Upgraded build plugin

Which version?

thekalinga commented 8 years ago

classpath 'com.android.tools.build:gradle:2.1.0-alpha1'

sockeqwe commented 8 years ago

Thats the problem! This version of the plugin uses Jack which does't support Annotation processing right now. Use another (older) one.

Ashok Koyi notifications@github.com schrieb am Mi., 16. März 2016, 04:10:

classpath 'com.android.tools.build:gradle:2.1.0-alpha1'

— You are receiving this because you modified the open/close state.

Reply to this email directly or view it on GitHub https://github.com/sockeqwe/fragmentargs/issues/50#issuecomment-197130193

thekalinga commented 8 years ago

Is 2.0.0-beta6 fine?. Can u please share the reference to the Jack issue if you have.

Thanks

sockeqwe commented 8 years ago

2.0.0-beta6 should be fine. Since jack doesn't use javac annotation processing is not supported (yet). http://tools.android.com/tech-docs/jackandjill (Scroll down to Compilation support)

thekalinga commented 8 years ago

The compiler for some reason is masking other compilation errors & giving only the fragmentargs *Builder related errors if I compile the latest code. Finally the issue is resolved after reverting the code to an older version and applying the changes step by step. Tho the issue is resolved for now, I'm not sure what might be causing this compilation error masking.

Overall, there were multiple compilation errors in the code, but the final build output(before fixing these compilation errors) did not contain these errors. I have apply each change in the latest code onto the older version and compile each step to find the actual compilation issues.

For now, I'm using 2.0.0-beta6, but this compilation error masking issue is independent of the 2.1.0-alpha1

Thanks for your suggestion.

thekalinga commented 8 years ago

Today I faced the same issue with new changes & could not figure out why its happening again.

After following same procedure as before, it seems these compilation error is due to the fact that one of the @Arg is neither parcellable/serializable. Due to this FragmentArgs is not generating the required *FragmentBuilder.

This is causing the overall build to fail, but non of the compilation errors are referring to this error (that the given arg is not Parcellable/Serializable). After I made the specific class Parcellable (I'm using ParcellablePlease), these long compilation error chain went off.

This not fails the build, but also masks other compilation errors.

I have faced the same issue before aswell. Since there were other compilation errors well, I had trouble in narrowing down the issue last time.

Can you please fix this issue.

sockeqwe commented 8 years ago

Hm, can you write me me a sample class to reproduce that? So you have put an @Arg annotation on something that is not Parcelable, right? Something like this:

public class NotParcelableClass {
  String foo;
}
@FragmentWithArgs
public abstract class TestFragment extends Fragment {

  @Arg
  int a;

  @Arg
  NotParcelableClass notParcelable;
}

Then I get an error message:

Error:(17, 22) error: Don't know how to put com.hannesdorfmann.fragmentargstest.NotParcelableClass in a Bundle. This type is not supported by default. However, you can specify your own ArgsBundler implementation in @Arg( bundler = YourBundler.class)
thekalinga commented 8 years ago

I tried on an empty project & am not able to reproduce this. I too, I am getting the same error as you have mentioned.

But in my main project, on a project that's just compiled successfully, if I make one of the model (the model that gave me trouble earlier) not parcellable, the compilation fails (with large number of compilation errors saying *Builder could not be found) and none of the compilation errors indicate that the failure is due to serialization.

The generated Builder class is partial (as expected for the fragment that contained this model).

I have tried reproducing this in a sample project with multiple other plugins (ones I have used in my main project) to see if this error is due to complex interaction between multiple plugins. Even then, I'm unable to reproduce this in the sample.

The behavior of compilation failing is something I am consistently able to reproduce in my main project (which has ~50-75 fragments). Not sure how/why its not happening in sample project.

Sorry, I'm not able to reproduce on a clean slate right now.

sockeqwe commented 8 years ago

Silly question, but are you sure that all between those *Builder could not be found error messages is not the one saying

Don't know how to put FooClass in a Bundle. This type is not supported by default. However, you can specify your own ArgsBundler implementation in @Arg( bundler = YourBundler.class)

What do you mean with:

The generated Builder class is partial (as expected for the fragment that contained this model).

thekalinga commented 8 years ago

No. I did not find any such statement (know how to put) in the build log. Generated using ./gradlew clean assembleDevOffline --debug --stacktrace 2>&1 >debug.txt

I have attached the log for your reference.

debug.txt

sockeqwe commented 8 years ago

I don't see any error in you logs at all ... could you please do a simple ./gradlew clean assembleDevOffline (without debug and stacktrace info)

thekalinga commented 8 years ago

Sorry. the command I ran was wrong. It din't output the stdout & stderr to the file.

I re-ran it with the correct command this time around (without debug & stacktrace options) ./gradlew clean assembleDevOffline >debug.txt 2>&1

I have attached the output. The POJO that I have added as an @Arg is DriverRequest & I commented out the code that's responsible for Parcelling this object. The Fragment that this POJO is included is DriverLanguageSelectionFragment

@FragmentWithArgs
public class DriverLanguageSelectionFragment extends BaseMvpFragment<DriverLanguageSelectionView, DriverLanguageSelectionPresenter>
        implements DriverLanguageSelectionView, PopConfirmationRequiredFragment {
    // Some @Bind, @Injects here
    @Arg(required = false)
    Driver driver;

    @Arg
    boolean quickCapture;

    @Arg
    DriverRequest newDriverRequest; // <<<---- This is the POJO of interest
    // Some fragment related code
}
@Data
@Builder
//@NoArgsConstructor
//@AllArgsConstructor
//@ParcelablePlease
public class DriverRequest {
//    implements Parcelable {

    transient long id;
    String name;
// a lot more fields

//    @Override
//    public int describeContents() {
//        return 0;
//    }
//
//    @Override
//    public void writeToParcel(Parcel dest, int flags) {
//        DriverRequestParcelablePlease.writeToParcel(this, dest, flags);
//    }
//
//    public static final Creator<DriverRequest> CREATOR = new Creator<DriverRequest>() {
//        public DriverRequest createFromParcel(Parcel source) {
//            DriverRequest target = new DriverRequest();
//            DriverRequestParcelablePlease.readFromParcel(target, source);
//            return target;
//        }
//
//        public DriverRequest[] newArray(int size) {
//            return new DriverRequest[size];
//        }
//    };
}

debug.txt

sockeqwe commented 8 years ago

I'm sorry, I can't spot any issue and therefore don't know if and where a bug of FragementArgs might be and how and what to fix.

Are you really sure that there is no other bug in your code (or another annotation processor) that prevents FragmentArgs annotation processor to run, because I'm pretty sure that FragmentArgs Annotation processor hasn't run, because otherwise the error know how to put ... must be there.

thekalinga commented 8 years ago

The moment I switch on the @Parcellable, compilation succeeds.

I'll keep trying to see if I can reproduce the issue on the sample project. Will post an update here if I can narrow down the issue.

Thanks for your help!!

thekalinga commented 8 years ago

Finally, found the root cause of the issue.

The reason for this masking is due to the fact that java compiler automatically restricts the number of compilation errors to ~100. Beyond this, its just does not output these errors (makes sense, since if the project has >100 compilation errors, it would be better for the user to fix each of this 100 errors, before proceeding with next batch of compilation errors).

If you have a lot of fragments like I have in my project which uses fragmentargs, for any compilation error in the project (errors that has nothing to do with fragmentargs), fragmentargs pollutes & bloats the number of compilation errors. Which would mean that the illegitimate compilation errors of fragmentargs pollute the real ones.

To save myself from this issue, I forced the javac to output first 1000 compilation errors, which is currently outputting the real compilation errors (in my current project, the single compilation error I had was pushed to 134th position, i.e last one, by all the dummy compilation errors of fragmentargs).

I made the following change to force compiler to output 1000 errors instead of default 100

allprojects {
    repositories {
        jcenter()
    }
    // <<-- change start
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xmaxerrs" << "1000"
        }
    }
    // <<-- change end
}

Like I said earlier, even, dagger generates code & when there is any compilation error in code other than dagger, it does not produce any dummy compilation errors. Is it possible(and of course easy) for you to make fragmentargs not to pollute the compilation errors/atleast make these compilation errors go to the end, so that you will still see the actual compilation error at the top?

In the mean time, can you please add this caveat to the documentation for now, so that others will not face this issue.

Thanks for your support.

Source: http://stackoverflow.com/a/35707023/211794

sockeqwe commented 8 years ago

Thanks for investing time on that and to let me know what the real problem is. I will add that to the read me.

So you have an error know how to put ... on position 134, right? So FragmentsArgs per se is working as expected and prints the correct error message?

Like I said earlier, even, dagger generates code & when there is any compilation error in code other than dagger, it does not produce any dummy compilation errors.

I have to dive deeper into dagger's source code, but I don't think that there is something magically in dagger that influences position of error message. Maybe there is something that influences that javac doesn't continue that I can adapt to FragmentArgs, but I think the biggest difference between FragmentArgs and Dagger is the way how the public API is designed.

In dagger2 usually you setup just one (or a few) components. So basically you have the generated class by dagger like DaggerFooComponent only in one place (usually Application class). So javac. may not find DaggerFooComponent, but there are not more than 100 places in your apps code where you have to access DaggerFooComponent. Furthermore, with dagger 2 you are implementing against a component interface you have defined. That also indirectly prevents javac from printing more error messages, because whenever you need a something from DaggerFooComponent in your apps source code you are programming again interface FooComponent which indeed is always there because it's not generated by annotation processor but you have defined that manually.

So from my understanding the reason why dagger2 is working better with annotation processing errors is mainly because there is only a few lines of code where you reference dagger generated classes like DaggerFooComponent, whereas in FragmentArgs you are using generated classes like FooFragmentBuilder in many places.

If you are using dagger 1, then it is all hidden behind ObjectGraph which is composed from generated classes at runtime by reflections.

Again, thank you very much for your patience and help! I will try to find time in April to elaborate solutions for that ...

sockeqwe commented 8 years ago

I think I have a point to improve that, by only not generating the Builder for those fragments who are annotated properly, see #51 . Right now, if one Fragment is not annotated properly causes that no Builder is generated.

sockeqwe commented 8 years ago

@thekalinga I think I have found a way so that only the not properly annotated fragment will throw an error. Can you please verify that this works on your project as well with latest 4.0.0-SNAPSHOT.

You have to add snapshot repository to your build.gradle:

allprojects {
  repositories {
    jcenter()
    maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
   }
}
thekalinga commented 8 years ago

Sorry for the delay in responding. Was occupied with some work at my end.

Yes, fragmentargs is outputting the errors properly.

I tried with 4.0.0-SNAPSHOT after updating maven repos as you mentioned. I still see the same issue (135 compilation errors, of which the dont know how to put is the last error).

Build & dependency tree logs are attached. Please do let me know if you need anything else.

./gradlew clean assembleDevOffline >debug.txt 2>&1 ./gradlew app:dependencies --configuration apt >dependencies-apt.txt 2>&1 ./gradlew app:dependencies --configuration compile >dependencies-compile.txt 2>&1

debug.txt dependencies-apt.txt dependencies-compile.txt