Glide: Annotation Processor Error

Created on 12 Aug 2017  路  6Comments  路  Source: bumptech/glide

Glide Version: 4.0.0
Integration libraries: okhttp3-4.0.0

I'm getting the following error in my application indicating to me that I'm not running my annotation processor, when I am:

08-12 11:44:45.559 1053-1374/com.google.android.googlequicksearchbox:search W/Glide: Failed to find GeneratedAppGlideModule. You should include an annotationProcessor compile dependency on com.github.bumptech.glide:glide:compiler in your application and a @GlideModule annotated AppGlideModule implementation or LibraryGlideModules will be silently ignored

Explanation: This error is happening, because Glide is requiring that I run the annotation processor on my actual android application module rather than on a library module. The only way to get good performance out of annotation processors is to avoid running them altogether through compile-avoidance and caching, otherwise if the code the annotation processor is attached to is compiled, the annotation processors have to run.

I created a small library module that was at the very end of the module dependency chain and used it to configure glide, and run the annotation processor. Instead, when I use Glide in this manner it gives me the above error, and forces me to move my annotation processor to my actual application. As soon as I do that, it no longer complains and works.

Request / Expectations / Bug: Glide's Annotation Processor should be able to be run on a smaller library module so that Glide's Annotation Processor isn't forced to be run on every single incremental Android build for the application. An approach I'd be even happier with it, is allow configuration 100% without an annotation processor, so that the annotation processor isn't required at all.

Question / comments: Why did Glide go the annotation processor direction? It seems like Glide is only using the annotation processor to generate a GlideApp that is properly configured, and to add custom configuration functions.

  • It seems like configuration can be done at runtime, cheaply, without annotation processors.
  • I like how this approach allows deferred configuration, but I think deferred configuration can be accomplished in other ways as well. I dislike how this approach silos configuration off into this separate module of your application that other parts of the application can't touch. That makes getting configuration information such as which server you are using, custom request header information, or even re-using the same http client difficult, as it requires it to be all in static variables.
  • People are starting to realize just how much annotation processors can hurt build performance, especially with Kotlin, and are trying to keep them out of their code.
question stale

Most helpful comment

There aren't many other alternatives for initialization, the previous one we tried (metadata in AndroidManifest.xml) is broken on some devices or for apps with sufficiently complex manifests.

It seems like with your previous manifest meta-data approach, and now your annotation processor approach, you really want the ability to just include a dependency, and have everything just magically work and stitch itself together. I think that can potentially work for the default case, but you can see from my ticket here ( https://github.com/bumptech/glide/issues/2238 ), I'm having to disable that behavior and manually stitch things together myself in a relatively unintuitive way for something as minor as adding a header to my image requests.

My opinion is that the builder API is less magical and more intuitive.

Glide glide = new Glide.Builder()
  .withLibrary(new OkHttpLibraryGlideModule(customHttpClient)) 
  .build();
Glide.setSingletonInstance(glide);

I also find it fairly difficult to get custom information into my AppGlideModule as I don't have control over the constructor. For instance, my company uses an API manager, and our testing and production environments use different API keys. I need to somehow pass the current server information to the AppGlideModule, so I can add the api key header to all of the requests. I'm forced to use 1 of 2 options, none of which feel right:

  1. Get that information before the AppGlideModule is constructed, and set it in a static field somewhere, where the AppGlideModule can read it. (Which becomes even more difficult when you are trying to move your AppGlideModule into a library so that the annotation processor doesn't have to run each build)
  2. Pass the information somehow through the context, i.e. by overriding getSystemService on the Activity or Application.

All 6 comments

For the functionality the annotations provide, see http://bumptech.github.io/glide/doc/generatedapi.html. There aren't many other alternatives for initialization, the previous one we tried (metadata in AndroidManifest.xml) is broken on some devices or for apps with sufficiently complex manifests.

Glide's annotation processor will run on libraries. The only requirements are that you have exactly one AppGlideModule and that the library containing the AppGlideModule depends on any LibraryGlideModules you want to include. We actually use this approach in Photos.

If you have some data that quantifies the amount of time Glide's annotation processor adds to builds, feel free to open an issue and we can see what we can do to minimize it.

@sjudd I have exactly one AppGlideModule. I'm still seeing the 'annotation processor has not been run' message intermittently, when everything has been setup properly to use the annotation processor. Now I'm not seeing the message, but an hour and a half ago I was. I haven't noticed any issues with using Glide though, but right now I'm only using it in a very small location in my app.

There aren't many other alternatives for initialization, the previous one we tried (metadata in AndroidManifest.xml) is broken on some devices or for apps with sufficiently complex manifests.

It seems like with your previous manifest meta-data approach, and now your annotation processor approach, you really want the ability to just include a dependency, and have everything just magically work and stitch itself together. I think that can potentially work for the default case, but you can see from my ticket here ( https://github.com/bumptech/glide/issues/2238 ), I'm having to disable that behavior and manually stitch things together myself in a relatively unintuitive way for something as minor as adding a header to my image requests.

My opinion is that the builder API is less magical and more intuitive.

Glide glide = new Glide.Builder()
  .withLibrary(new OkHttpLibraryGlideModule(customHttpClient)) 
  .build();
Glide.setSingletonInstance(glide);

I also find it fairly difficult to get custom information into my AppGlideModule as I don't have control over the constructor. For instance, my company uses an API manager, and our testing and production environments use different API keys. I need to somehow pass the current server information to the AppGlideModule, so I can add the api key header to all of the requests. I'm forced to use 1 of 2 options, none of which feel right:

  1. Get that information before the AppGlideModule is constructed, and set it in a static field somewhere, where the AppGlideModule can read it. (Which becomes even more difficult when you are trying to move your AppGlideModule into a library so that the annotation processor doesn't have to run each build)
  2. Pass the information somehow through the context, i.e. by overriding getSystemService on the Activity or Application.

Builder APIs are certainly easier to use, but they're also very easy to get wrong. It's difficult to guarantee that your call happens only when the library is used and before any request is made. Failing to do so can lead to randomly broken loading, or worse, security issues if the wrong library is used.

A common answer to injecting information would be to use a dependency injection framework.

If you don't want to go that far, you could also just define a static method that both your module and your API manager can all to get the current server info. That may be more difficult depending on your library set up though.

A common answer to injecting information would be to use a dependency injection framework.

This is the approach I have working currently. I'm exposing the dependency graph to the glide module through getSystemService.

This issue has been automatically marked as stale because it has not had activity in the last seven days. It will be closed if no further activity occurs within the next seven days. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

technoir42 picture technoir42  路  3Comments

billy2271 picture billy2271  路  3Comments

sergeyfitis picture sergeyfitis  路  3Comments

PatrickMA picture PatrickMA  路  3Comments

Morteza-Rastgoo picture Morteza-Rastgoo  路  3Comments