cannot be provided without an #Provides-annotated method -- - Confusedddd - dependency-injection

Error:(39, 10) error: [Dagger/MissingBinding] kz.production.kuanysh.sellings.ui.content_owner.fragments.order.orders.OrdersFragmentPresenter cannot be provided without an #Provides-annotated method.
kz.production.kuanysh.sellings.ui.content_owner.fragments.order.orders.OrdersFragmentPresenter is injected at
kz.production.kuanysh.sellings.ui.content_owner.fragments.order.orders.OrdersFragment.mPresenter
kz.production.kuanysh.sellings.ui.content_owner.fragments.order.orders.OrdersFragment is injected at
kz.production.kuanysh.sellings.di.component.ActivityComponent.inject(kz.production.kuanysh.sellings.ui.content_owner.fragments.order.orders.OrdersFragment)
Component :
#PerActivity
#Component(dependencies = ApplicationComponent.class, modules =
ActivityModule.class)
public interface ActivityComponent {
void inject(MainActivity activity);
void inject(LoginActivity activity);
void inject(OwnerSupplierItemFragment ownerSupplierItemFragment);
void inject(OrdersFragment ordersFragment);
}
In module class :
#Module
public class ActivityModule {
private AppCompatActivity mActivity;
public ActivityModule(AppCompatActivity activity) {
this.mActivity = activity;
}
#Provides
#ActivityContext
Context provideContext() {
return mActivity;
}
#Provides
AppCompatActivity provideActivity() {
return mActivity;
}
#Provides
CompositeDisposable provideCompositeDisposable() {
return new CompositeDisposable();
}
#Provides
SchedulerProvider provideSchedulerProvider() {
return new AppSchedulerProvider();
}
#Provides
#PerActivity
LoginMvpPresenter<LoginMvpView> provideLoginPresenter(
LoginPresenter<LoginMvpView> presenter) {
return presenter;
}
#Provides
#PerActivity
MainMvpPresenter<MainMvpView> provideMainPresenter(
MainPresenter<MainMvpView> presenter) {
return presenter;
}
/*#Provides
OrdersFragmentMvpPresenter<OrdersFragmentMvpView> provideOrdersFragmentPresenter(
OrdersFragmentPresenter<OrdersFragmentMvpView> presenter) {
return presenter;
}*/
#Provides
#PerActivity
OrdersFragmentMvpPresenter<OrdersFragmentMvpView> provideOrdersFragmentPresenter(
OrdersFragmentPresenter<OrdersFragmentMvpView> presenter){
return presenter;
}
#Provides
#PerActivity
OwnerSupplierItemMvpPresenter<OwnerSupplierItemMvpView> provideOwnerSupplierItemPresenter(
OwnerSupplierItemPresenter<OwnerSupplierItemMvpView> presenter) {
return presenter;
}
#Provides
LinearLayoutManager provideLinearLayoutManager(AppCompatActivity activity) {
return new LinearLayoutManager(activity);
}
}
My presenter
public class OrdersFragmentPresenter<V extends OrdersFragmentMvpView> extends
BasePresenter<V>
implements OrdersFragmentMvpPresenter<V> {
#Inject
public OrdersFragmentPresenter(DataManager dataManager, SchedulerProvider schedulerProvider, CompositeDisposable compositeDisposable) {
super(dataManager, schedulerProvider, compositeDisposable);
}
#Override
public void onViewPrepared() {
//getMvpView().updateOrders();
}
#Override
public void onDetailClick(int position) {
getMvpView().openOrderDetailFragment();
}
}

So the issue is that you are using
OrdersFragmentPresenter
But you are never providing it, so dagger will not know how to get an instance of this.
#Provides
OrdersFragmentMvpPresenter<OrdersFragmentMvpView> provideOrdersFragmentPresenter(
OrdersFragmentPresenter<OrdersFragmentMvpView> presenter) {
return presenter;
}
So you need to add something like
#Provides
OrdersFragmentPresenter<OrdersFragmentMvpView> provideOrdersFragmentPresenter(
) {
return new OrdersFragmentPresenter(); //something like this;
}
Also, you should be careful using custom scopes in the module. As a good practice, each module should be providing elements for only one scope.

Related

Google Guice binding using Annotation and Key class

Lets say we have A.java interface implemented by AImpl.java and B.java implemented by Bimpl.java
Above classes are binded in two modules as below
Module1 {
bind(A.class).to(AImpl.class);
bind(B.class).to(BImpl.class);
}
Module2 {
Key<A> aKey = Key.get(A.class, AnAnnot.class);
bind(aKey).to(AImpl.class);
Key<B> bKey = Key.get(B.class, AnAnnot.class);
bind(bKey).to(BImpl.class);
}
Class AImpl implements A {
}
Class BImpl implements B {
#Inject
BImpl(A aImpl) {
//??
}
}
BImpl refers to A
For BImpl binded using Annotation, I want corresponding aImpl, binded using Annotation but here I'm getting aImpl which is not binded using Annotation
Please suggest
I'm able to achieve using below pattern. May be there is a more easier way. Happy to know more
A.java
public interface A {
String aMethod();
}
AImpl.java
public class AImpl implements A {
private String moduleName;
public AImpl(String moduleName) {
this.moduleName = moduleName;
}
#Override
public String aMethod() {
return moduleName;
}
}
B.java
public interface B {
String bMethod();
}
Bimpl.java
public class BImpl implements B {
private final A a;
BImpl(A a) {
this.a = a;
}
#Override
public String bMethod() {
return a.aMethod();
}
}
AnAnnot.java
#Target(PARAMETER)
#Retention(RUNTIME)
#BindingAnnotation
public #interface AnAnnot {
}
BProvider.java
public class BProvider implements Provider<B> {
private final A a;
#Inject
BProvider(A a) {
this.a = a;
}
#Override
public B get() {
return new BImpl(a);
}
}
BHavingAnnotatedA.java
public class BHavingAnnotatedA implements Provider<B> {
private final A a;
#Inject
BHavingAnnotatedA(#AnAnnot A a) {
this.a = a;
}
#Override
public B get() {
return new BImpl(a);
}
}
ABModule1.java
public class ABModule1 extends AbstractModule {
#Override
protected void configure() {
bind(A.class).to(AImpl.class);
bind(B.class).toProvider(BProvider.class);
}
}
ABModule2.java
public class ABModule2 extends AbstractModule {
#Override
protected void configure() {
Key<A> aKey = Key.get(A.class, AnAnnot.class);
bind(aKey).to(AImpl.class);
Key<B> bKey = Key.get(B.class, AnAnnot.class);
bind(bKey).toProvider(BHavingAnnotatedA.class);
}
}

Dagger generated code compilation failed when using #Singleton annotation

I am using Dagger - 2.6 and i have the following classes.
public class Trigger {
public static JSONObject triggerLambda(JSONObject jsonObject) {
DataTransformerComponent daggerDataTransformerComponent = DaggerDataTransformerComponent.create();
return daggerDataTransformerComponent.getHandler().handle(jsonObject);
}
}
Data Handler class:
public class DataHandler {
private static final Logger LOGGER = Logger.getLogger(DataHandler.class.getName());
private A a;
#Inject
public DataHandler(A a) {
this.a = a;
}
public JSONObject handle(JSONObject input) {
LOGGER.info("Json input received - " + input.toString());
return a.executeTransformation(input);
}
}
And a dependency:
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
My component class looks like:
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
When i compile the above code it runs absolutely fine.
Now i want to make my A dependency #Singleton.
So i change my dependency class and component class as follows:
#Singleton
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
Dependency class:
#Singleton
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
But now the generated component shows compilation errors saying:
A_Factory not found and it fails in the initialize() method.
DaggerDataTransformerComponent :
#Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerDataTransformerComponent implements DataTransformerComponent {
private Provider<A> aProvider;
private Provider<DataHandler> dataHandlerProvider;
private DaggerDataTransformerComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static DataTransformerComponent create() {
return builder().build();
}
#SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.aProvider = DoubleCheck.provider(A_Factory.create());
this.dataHandlerProvider = DataHandler_Factory.create(aProvider);
}
#Override
public DataHandler getHandler() {
return dataHandlerProvider.get();
}
public static final class Builder {
private Builder() {}
public DataTransformerComponent build() {
return new DaggerDataTransformerComponent(this);
}
}
}
I am unable to figure out why it does not create _factory class when i use #Singleton annotation.?.
Just use regular JavaScript + node.js, its a lot simpler

Dagger 2 multiple Repositories

So i am new to Dagger 2 dependency injection. I have created a custom ViewModelFactory class which returns my ViewModel.
#Singleton
public class CustomViewModelFactory implements ViewModelProvider.Factory {
private final MyCatchesRepository repository;
#Inject
public CustomViewModelFactory(MyCatchesRepository repository) {
this.repository = repository;
}
#NonNull
#Override
#SuppressWarnings("unchecked")
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
if (modelClass.isAssignableFrom(MyCatchViewModel.class)) {
return (T) new MyCatchViewModel(repository);
} else {
throw new IllegalArgumentException("ViewModel Not Found");
}
}
}
The CustomViewModel takes a MyCatchesRepository in the constructor and then creates the MyCatchViewModel.
How could i change this class so that i can use this ViewModelFactory to create different ViewModels with different constructor arguments (repositories)
This is the Module where the CustomViewModelFactory is created
#Module
public class RoomModule {
private final MyDatabase myDatabase;
public RoomModule(Application application) {
this.myDatabase = Room.databaseBuilder(application,
MyDatabase.class, AppConstants.DATABASE_NAME)
.build();
}
#Provides
#Singleton
MyCatchesRepository provideCatchesRepository(MyCatchDao myCatchDao) {
return new MyCatchesRepository(myCatchDao);
}
#Provides
#Singleton
MyCatchDao providesCatchDao(MyDatabase myDatabase) {
return myDatabase.myCatchDao();
}
#Provides
#Singleton
LuresRepository provideLureRepository(LureDao lureDao) {
return new LuresRepository(lureDao);
}
#Provides
#Singleton
LureDao provideLureDao(MyDatabase myDatabase) {
return myDatabase.lureDao();
}
#Provides
#Singleton
MyDatabase provideDatabase(Application application) {
return myDatabase;
}
#Provides
#Singleton
ViewModelProvider.Factory provideCatchesViewModelFactory(MyCatchesRepository catchesRepository) {
return new CustomViewModelFactory(catchesRepository);
}
}
ViewModelModule
#Module
public abstract class ViewModelModule {
#Binds
#IntoMap
#ViewModelKey(MyCatchViewModel.class)
abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);
#Binds
#IntoMap
#ViewModelKey(FishingSpotViewModel.class)
abstract ViewModel fishingSpotViewModel(FishingSpotViewModel fishingSpotViewModel);
#Binds
abstract ViewModelProvider.Factory bindCustomViewModelFactory(CustomViewModelFactory customViewModelFactory);
}
The approach the Google team came up with in the architecture components samples is to use a custom annotation in order to provide ViewModel classes through dagger.
In Java the Annotation looks as follows.
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import androidx.lifecycle.ViewModel;
import dagger.MapKey;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#MapKey
#interface ViewModelKey {
Class<? extends ViewModel> value();
}
This uses MapKey from Dagger, where any annotated ViewModel will be composed into a Map which can then be used in your ViewModelFactory.
In the Google samples the ViewModelFactory looks as follows, where using constructor injection you can access the map of ViewModel providers.
public class ViewModelFactory implements ViewModelProvider.Factory {
private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels;
#Inject
public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModels) {
this.viewModels = viewModels;
}
#NonNull
#Override
public <T extends ViewModel> T create(#NonNull Class<T> modelClass) {
Provider<ViewModel> viewModelProvider = viewModels.get(modelClass);
if (viewModelProvider == null) {
throw new IllegalArgumentException("model class " + modelClass + " not found");
}
//noinspection unchecked
return (T) viewModelProvider.get();
}
}
In your example your would end up with the following in order to provide the MyCatchViewModel. Other ViewModels could then be provided by following the same pattern.
#Module
public abstract class ViewModelModule {
#Binds
#IntoMap
#ViewModelKey(MyCatchViewModel.class)
abstract ViewModel myCatchViewModel(MyCatchViewModel myCatchViewModel);
}
For a complete example you can check out the GithubBrowserSample sample from Google. https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/ViewModelModule.kt

How to use Glide with dagger2

I am developing a music application. I want to load artist's image from LastFM so i do this this way
1. I created a class ArtistImageLoader extends BaseGlideUrlLoader.
2. In the getUrl method i used retrofit2 to get the artist's image url from LastFM via getArtistInfo method.
My problem is i didn't know how to inject the service of retrofit to make the request in ArtistImageLoader. I did this way but i got a NOP exception. lastFmService wasn't be not injected.
// GlideModule
glide.register(MLocalArtist.class, InputStream.class, new ArtistImageLoader.Factory());
// Use it in onCreate method of ArtistsFragment
DaggerLastFmComponent.builder().activityModule(new ActivityModule(getActivity()))
.netComponent(getNetComponent())
.build().inject(this);
// use this code in onBindViewHolder method of artists recycler adapter
Glide.with(getContext())
.from(MLocalArtist.class)
.load(localArtist)
.into(localArtistViewHolder.ivArtwork);
ArtistImageLoader
public class ArtistImageLoader extends BaseGlideUrlLoader<MLocalArtist> {
#Inject
LastfmService lastfmService;
public ArtistImageLoader(Context context) {
super(context);
}
#Override
protected String getUrl(MLocalArtist model, int width, int height) {
Call<List<MArtist>> call = lastfmService.getArtistInfo(model.artistName);
try {
List<MArtist> artists = call.execute().body();
if (artists != null && artists.size() > 0) {
Timber.e(artists.get(0).toString());
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static class Factory implements ModelLoaderFactory<MLocalArtist, InputStream> {
#Override public ModelLoader<MLocalArtist, InputStream> build(Context context, GenericLoaderFactory factories) {
return new ArtistImageLoader(context);
}
#Override public void teardown() {
}
}
}
Can you help me to do it? Thank you so much!
Glide Version: 3.7.0
Integration libraries: OkHttp3 + Dagger2
Device/Android Version: Android Emulator + Asus zenfone 5
EDIT 1
ActivityComponent.java
#PerActivity
#Component(dependencies = AppComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
Context context();
}
AppComponent.java
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
App app();
}
NetComponent.java
#Singleton
#Component(modules = {NetModule.class, AppModule.class})
public interface NetComponent {
#Named("chartSoundCloud")
Retrofit getSoundcloudChartRetrofit();
#Named("searchSoundCloud")
Retrofit getSoundcloudSearchRetrofit();
#Named("lastFM")
Retrofit getLastFmRetrofit();
}
LastFmComponent.java
#PerActivity
#Component(dependencies = NetComponent.class, modules = {LastFmModule.class, ActivityModule.class})
public interface LastFmComponent extends ActivityComponent {
void inject(ArtistsFragment artistsFragment);
}
ActivityModule.java
#Module
public class ActivityModule {
private final Context mContext;
public ActivityModule(Context mContext) {
this.mContext = mContext;
}
#Provides
#PerActivity
Context provideActivityContext() {
return mContext;
}
}
AppModule.java
#Module
public class AppModule {
private App app;
public AppModule(App app){
this.app = app;
}
#Singleton
#Provides
App provideApplication() {
return app;
}
#Singleton
#Provides #Named("applicationContext")
Context provideApplicationContext(){
return app;
}
}
LastFmModule.java
#Module
public class LastFmModule {
#Provides
#PerActivity
LastfmService provideLastFmService(#Named("lastFM") Retrofit retrofit) {
return retrofit.create(LastfmService.class);
}
}
NetModule.java
#Module
public class NetModule {
static final int DISK_CACHE_SIZE = (int) MEGABYTES.toBytes(50);
#Provides
#Singleton
Cache provideOkHttpCache(#Named("applicationContext") Context application) {
Cache cache = new Cache(application.getCacheDir(), DISK_CACHE_SIZE);
return cache;
}
#Provides
#Singleton
ScdClientIdInterceptor provideScdClientIdInterceptor() {
return new ScdClientIdInterceptor();
}
#Provides
#Singleton
LastFMInterceptor provideLastFmInterceptor() {
return new LastFMInterceptor();
}
#Provides
#Singleton
HttpLoggingInterceptor provideHttpLoggingInterceptor() {
return new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);
}
#Provides
#Singleton
#Named("soundcloud-Http")
OkHttpClient provideOkHttpSoundCloudClient(Cache cache, ScdClientIdInterceptor clientIdInterceptor, HttpLoggingInterceptor httpLoggingInterceptor) {
return createOkHttpClient(cache, clientIdInterceptor, httpLoggingInterceptor);
}
#Provides
#Singleton
#Named("lastFM-Http")
OkHttpClient provideOkHttpLastFmClient(Cache cache, LastFMInterceptor clientIdInterceptor, HttpLoggingInterceptor httpLoggingInterceptor) {
return createOkHttpClient(cache, clientIdInterceptor, httpLoggingInterceptor);
}
private OkHttpClient createOkHttpClient(Cache cache, Interceptor clientIdInterceptor, HttpLoggingInterceptor httpLoggingInterceptor) {
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.cache(cache)
.addInterceptor(clientIdInterceptor)
.addInterceptor(httpLoggingInterceptor)
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
return okHttpClient;
}
#Provides
#Singleton
Gson provideGson() {
return GsonFactory.create();
}
#Provides
#Singleton
#Named("searchSoundCloud")
Retrofit provideSearchSoundCloudRetrofit(Gson gson, #Named("soundcloud-Http") OkHttpClient okHttpClient) {
Retrofit searchRetrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_SOUNDCLOUD_API_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return searchRetrofit;
}
#Provides
#Singleton
#Named("chartSoundCloud")
Retrofit provideChartSoundCloudRetrofit(Gson gson, #Named("soundcloud-Http") OkHttpClient okHttpClient) {
Retrofit chartRetrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_SOUNDCLOUD_API_V2_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return chartRetrofit;
}
#Provides
#Singleton
#Named("lastFM")
Retrofit provideLastFmRetrofit(Gson gson, #Named("lastFM-Http") OkHttpClient okHttpClient) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.LASTFM_API_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return retrofit;
}
}
My assumption is that your ArtistImageLoader is defined in an separate class. The reason for the your problem is the way dagger works. It only injects fields annotated with #Inject on the class you specified as parameter of the inject method. Therefore nothing inside your ArtistImageLoader annotated with #Inject will be injected, but only the annotated fields, which are defined inside your ArtistsFragment.
I would recommend to define an LastfmService field with the #Inject annotation in your fragment and pass the instance to your Glide LoaderFactory. The factory can provide it to the instances of the loader. It's not the nicest solution, but since you can't directly pass it to the instances this seems to viable workaround.
Another approach would be to build your dependency tree inside your custom Application. This allows you access the dependencies from anywhere without being dependent on the activity lifecycle.

Jersy2 inject slf4j Logger

I'm trying to understand Jersey 2 development and context-dependency injection.
I don't understand how to inject into a resource an object that needs initialization parameters in the constructor.
For example: I'd like to #Inject slf4j Logger, built using LoggerFactory.
My resource class is:
#Path("/myresource")
public class MyResource {
#Inject
private Logger log;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Answer status() {
log.info("STATUS");
return new Answer(200, "Server up and running # "+ ZonedDateTime.now());
}
}
My Resource config is:
public class MyAppextends ResourceConfig {
public MyApp() {
register(new MyBinder());
packages(true, "my.packages");
}
}
public class MyBinder extends AbstractBinder {
#Override
protected void configure() {
bindFactory(MyLoggerFactory.class).to(org.slf4j.Logger.class);
}
}
Finally, the Factory is:
public class MyLoggerFactory implements Factory<Logger> {
#Override
public Logger provide() {
return LoggerFactory.getLogger(TYPE_FOR_LOGGING.class);
}
#Override
public void dispose(Logger logger) {
}
}
How can I specify TYPE_FOR_LOGGING as argument, in order to Inject the correctly initialized Logger in every resource I want?
Thanks
What you are looking for is called the InstantiationService. You can inject it into Factories to find out who is calling the factory inside of the provide method.
Below find a code sample from the hk2 tests that illustrate the use of the InstantiationService.
#Singleton
public class CorrelationFactory implements Factory<PerLookupServiceWithName> {
private final static PerLookupServiceWithName NULL_SERVICE = new PerLookupServiceWithName() {
#Override
public String getName() {
return null;
}
};
#Inject
private InstantiationService instantiationService;
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#provide()
*/
#Override #PerLookup
public PerLookupServiceWithName provide() {
InstantiationData data = instantiationService.getInstantiationData();
if (data == null) {
return NULL_SERVICE;
}
Injectee parent = data.getParentInjectee();
if (parent == null) {
return NULL_SERVICE;
}
Class<?> parentClass = parent.getInjecteeClass();
if (parentClass == null) {
return NULL_SERVICE;
}
Correlator correlator = parentClass.getAnnotation(Correlator.class);
if (correlator == null) {
return NULL_SERVICE;
}
final String fName = correlator.value();
return new PerLookupServiceWithName() {
#Override
public String getName() {
return fName;
}
};
}
/* (non-Javadoc)
* #see org.glassfish.hk2.api.Factory#dispose(java.lang.Object)
*/
#Override
public void dispose(PerLookupServiceWithName instance) {
// DO nothing
}
}

Resources