Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove unnecessary MembersInjectors.injectMembers method #950

Closed
wants to merge 3 commits into from

Conversation

szymonkozak
Copy link

@szymonkozak szymonkozak commented Nov 14, 2017

The last use of the MembersInjectors class was removed in this commit, so it isn't used now during code generation.
(This class is still used in TypeNames as a class name constant, which is no longer necessary)

Static MembersInjectors.injectMembers is no longer used during code generation.

* members, so care should be taken to ensure appropriate use.
*/
@SuppressWarnings("unchecked")
public static <T> MembersInjector<T> noOp() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may not have a test for it, but this is returned when for types that have no injected members:

class A {
  @Inject A() {}
}

@Component
interface C {
  MembersInjector<A> aMembersInjector();
}

}
}

public static void checkInstanceNotNull(Object instance) {
Copy link

@ronshapiro ronshapiro Nov 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is use above, but we can make it private probably

@@ -79,7 +78,6 @@
static final ClassName MAP_PRODUCER = ClassName.get(MapProducer.class);
static final ClassName MAP_PROVIDER_FACTORY = ClassName.get(MapProviderFactory.class);
static final ClassName MEMBERS_INJECTOR = ClassName.get(MembersInjector.class);
static final ClassName MEMBERS_INJECTORS = ClassName.get(MembersInjectors.class);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See MemberSelect.noOpMembersInjector()

Copy link
Author

@szymonkozak szymonkozak Nov 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, right.
So can I remove static injectMembers from MembersInjectors?. It's seems to be not used.

@@ -57,7 +48,7 @@
}
}

public static void checkInstanceNotNull(Object instance) {
private static void checkInstanceNotNull(Object instance) {
checkNotNull(instance, "Cannot inject members into a null reference");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just inline this above?

@szymonkozak szymonkozak changed the title Remove unnecessary MembersInjectors class Remove unnecessary MembersInjectors.injectMembers method Nov 14, 2017
@ronshapiro
Copy link

Great, thanks! We'll submit this internally and then sync a commit with your authorship here!

ronshapiro pushed a commit that referenced this pull request Nov 15, 2017
Closes #950

RELNOTES=n/a

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=175736999
@Tagakov
Copy link

Tagakov commented Dec 21, 2017

Hi, I am using a dependency which is built with old version of dagger. After updating to 2.14.1 I am facing crash when dependency mentioned above references to MembersInjectors.injectMembers which is not presented in current version anymore.

Exception description
java.lang.NoSuchMethodError: No static method injectMembers(Ldagger/MembersInjector;Ljava/lang/Object;)

Generated code from library

public OverlayPresenter get() {
    return (OverlayPresenter)MembersInjectors.injectMembers(this.overlayPresenterMembersInjector, new OverlayPresenter((PresenterConfiguration)this.presenterConfigurationProvider.get(), (BusinessInteractor)this.businessInteractorProvider.get()));
}

I am not sure how to fix it, can you help please?

@ronshapiro
Copy link

You should shade the dagger.internal from one (or both) of the libraries. The old one is probably easiest

@vovkab
Copy link

vovkab commented Jan 24, 2018

Any reason we did breaking changes to a "public" api?
It is not really internal if it is end up being used by client code, even if it is autogenerated.

@JakeWharton
Copy link

JakeWharton commented Jan 24, 2018 via email

@ronshapiro
Copy link

It's a good idea to be shading any dagger.internal.* code if you're sharing it with other libraries that are being compiled separately/that you can't guarantee are being compiled at the same dagger version.

@vovkab
Copy link

vovkab commented Jan 24, 2018

@JakeWharton That is all ok if you have access to code to generate.

If you are building a library using dagger, all code generation is already done. So we either should not change "public" api to keep it compatible, or we should do real client code generation to make sure there is no dagger dependencies left to worry about, i.e. internals should not be on a class path, generate anything you may need in clients namespace.

@tbroyer
Copy link

tbroyer commented Jan 25, 2018

I have to agree with @vovkab here, if generated code depends on dagger.internal.* then dagger.internal.* is part of the public API. If your answer is "shade it", then it at least needs to be properly documented (and then people will re-evaluate their use of Dagger in libraries –like they did for Guava for a while, before the recent change in policy– as it'll consequently bloat their apps with duplicate shaded code; and/or we'll likely see "forks" of the com.google.dagger:dagger artifact only to retain backwards compatibility).

@elye
Copy link

elye commented Nov 5, 2018

I facing this issue as well

java.lang.NoSuchMethodError: No static method injectMembers(Ldagger/MembersInjector;Ljava/lang/Object;)

What does the shade in You should shade the dagger.internal from one (or both) of the libraries. refers to?

@tbroyer
Copy link

tbroyer commented Nov 5, 2018

What does the shade in You should shade the dagger.internal from one (or both) of the libraries. refers to?

To https://maven.apache.org/plugins/maven-shade-plugin/ or anything similar for your build tool (e.g. https://imperceptiblethoughts.com/shadow/ for Gradle, https://github.com/google/bazel-common/blob/c0a6655a70fb389dbb6473989450df0c86447ec3/tools/jarjar/jarjar.bzl for Bazel, etc.)
and specifically to "relocating" classes under a different package.

@elye
Copy link

elye commented Nov 5, 2018

Thanks @tbroyer. I'm using gradle (Android Studio).
From the reference, sound the shading referring to a process that's packaging the jar.

What if I don't have control over the jar where I can't make changes to it, is there anything I could do?

P/S: I tried exclude as below so we could have a single dagger version used in my app, but it is not working

implementation(group: "my.package", name: "lib-name, version: "$ver") {
    exclude group: 'com.google.dagger'
}

Can I assume if the library uses the same dagger version as mine (e.g. both of us move to 2.19), then this would not be an issue?

@vovkab
Copy link

vovkab commented Nov 5, 2018

I tried exclude as below so we could have a single dagger version used in my app, but it is not working

I don't think this is going to work, this is the same as just specifying latest version.

The idea is that you would create local copy of the dagger library just with the different package name, so they all could co-exist in a single project. Though I think this is only would work for your app, not sure if you can repackage 3rd party libraries (or maybe you can?).

Can I assume if the library uses the same dagger version as mine (e.g. both of us move to 2.19), then this would not be an issue?

Yes, if your app and libraries use "compatible" dagger versions it would work, they don't have to use the same version.

p.s. this is really a pain for us, if we have 20 libraries that use 20 different versions of dagger and all these dagger versions are incompatible, we would need to repackage 20 libraries and 20 versions of dagger :'(

@tbroyer tbroyer mentioned this pull request Nov 15, 2018
@ronshapiro
Copy link

There's no guarantee that the generated code (i.e. factories) work well with each other across versions. We don't have any way of testing that. It's a generally good idea that any libraries that are intended to use Dagger in tandem are using the same version of Dagger.

If a library you don't own is passing along Dagger codegen to you and isn't documenting it, that's a bad idea on the library owners part.

In fairness, we don't really have a good way to share libraries across project owners that guaranteed support across multiple versions.

@vovkab
Copy link

vovkab commented Nov 15, 2018

There's no guarantee that the generated code (i.e. factories) work well with each other across versions.

They don't have to be, this is pre-generated code, the problem is in code that ships in dagger jar.

If a library you don't own is passing along Dagger codegen to you and isn't documenting it, that's a bad idea on the library owners part.

In my opinion, this really should not matter, this is an internal library code.

In fairness, we don't really have a good way to share libraries across project owners that guaranteed support across multiple versions.

We actually do, here are a couple suggestions:

  1. Everything that gets referenced from client code back to dagger jar is a public code and should remain backward compatible. (this is where the problem right now, we keep breaking "public" code and making minor versions incompatible with each other)
  2. Or/and - generate standalone di code. Copy any utils or classes generated code requires, into client namespace or inline them. This way we could keep generated code independent from dagger library.

@vovkab
Copy link

vovkab commented Jun 17, 2020

This is still an issue, for example now even google is packaging dagger2 into their libraries without creating a shadowed version:

+--- com.google.firebase:firebase-crashlytics:17.0.0
|    +--- com.google.android.datatransport:transport-backend-cct:2.2.1
|    |    +--- com.google.android.datatransport:transport-runtime:2.2.1
|    |    |    +--- com.google.android.datatransport:transport-api:2.2.0
|    |    |    \--- com.google.dagger:dagger:2.27

What this means is that if dagger library again introduce breaking change like this one, we would be stuck with 2.27 until google decide to update dagger version. What makes it even worse is that other libraries may use different versions of dagger which would be incompatible between each other.

Here is the firebase bug:
firebase/firebase-android-sdk#1677

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants