JakeWharton / dagger-reflect

A reflection-based implementation of the Dagger dependency injection library for fast IDE builds.
Apache License 2.0
655 stars 44 forks source link

Crash on java.lang.ClassNotFoundException: dagger.android.ContributesAndroidInjector #190

Open roxrook opened 4 years ago

roxrook commented 4 years ago

It crashed when I use this on server side application which has no Android deps. Is there a way to exclude Android specific dependencies?

Edited to add stacktrace:


java.lang.NoClassDefFoundError: dagger/android/ContributesAndroidInjector
    at dagger.reflect.ReflectiveModuleParser.parse(ReflectiveModuleParser.java:78)
    at dagger.reflect.ComponentScopeBuilder.get(ComponentScopeBuilder.java:124)
    at dagger.reflect.ComponentBuilderInvocationHandler.invoke(ComponentBuilderInvocationHandler.java:98)
JakeWharton commented 4 years ago

Yes. It's actually supposed to be set up to guard against this already...

TWiStErRob commented 4 years ago

Do you have an extra abstract method / interface method that's not @Binds nor @Multibinds somewhere in a @Module? (based on the if-else-if structure this is the only way to get this exception)

roxrook commented 4 years ago

So I actually went through the source code, and @TWiStErRob is absolutely right about that. I actually have an interface Logging in one of the modules 🤦. Apparently, regular Dagger does not complain about this at all, not sure if this is worth a change, however debugging it at the beginning is quite challenging due to kapt, I have to switch to the full reflect version to see that method.


          if (method.getAnnotation(Binds.class) != null) {
            Key key = Key.of(qualifier, returnType);
            Binding binding = new UnlinkedBindsBinding(method);
            addBinding(scopeBuilder, key, binding, annotations);
          } else if (method.getAnnotation(BindsOptionalOf.class) != null) {
            try {
              Key key =
                  Key.of(
                      qualifier,
                      new ParameterizedTypeImpl(null, Optional.class, boxIfNecessary(returnType)));
              Binding binding = new UnlinkedJavaOptionalBinding(method);
              addBinding(scopeBuilder, key, binding, annotations);
            } catch (NoClassDefFoundError ignored) {
            }
            try {
              Key key =
                  Key.of(
                      qualifier,
                      new ParameterizedTypeImpl(
                          null, com.google.common.base.Optional.class, boxIfNecessary(returnType)));
              Binding binding = new UnlinkedGuavaOptionalBinding(method);
              addBinding(scopeBuilder, key, binding, annotations);
            } catch (NoClassDefFoundError ignored) {
            }
          } else if (method.getAnnotation(Multibinds.class) != null) {
            Key key = Key.of(qualifier, returnType);
            if (method.getReturnType() == Set.class) {
              scopeBuilder.createSetBinding(key);
            } else if (method.getReturnType() == Map.class) {
              scopeBuilder.createMapBinding(key);
            } else {
              throw new IllegalStateException(
                  "@Multibinds return type must be Set or Map: " + returnType);
            }
          } else {
            ContributesAndroidInjector contributesAndroidInjector =
                method.getAnnotation(ContributesAndroidInjector.class);
            if (contributesAndroidInjector != null) {
              // TODO check return type is a supported type? not parameterized? something else?
              Class<?>[] modules = contributesAndroidInjector.modules();
              Class<?> androidType = (Class<?>) returnType;
              Binding.UnlinkedBinding binding =
                  new UnlinkedAndroidInjectorFactoryBinding(
                      modules, androidType, findScopes(annotations));
              addAndroidMapBinding(scopeBuilder, returnType, binding);
            }
          }
        } else {
          if (method.getAnnotation(Provides.class) != null) {
            ensureNotPrivate(method);
            if (!Modifier.isStatic(method.getModifiers()) && instance == null) {
              ensureNotAbstract(moduleClass);
              // Try to just-in-time create an instance of the module using a default constructor.
              instance = maybeInstantiate(moduleClass);
              if (instance == null) {
                throw new IllegalStateException(moduleClass.getCanonicalName() + " must be set");
              }
            }

            Key key = Key.of(qualifier, returnType);
            Binding binding = new UnlinkedProvidesBinding(instance, method);
            addBinding(scopeBuilder, key, binding, annotations);
          }
        }```