Google Guice ProvisionException: Unable to provision. No implementation was bound - java

New to DI and guice..
I want to use a service (StoreLevelClient) This is a class defined by other team.
I inject this class in my main file like this:
class ClientAccessor {
companion object {
private val LOGGER = KotlinLogging.logger { }
}
private val myStoreLevelClient: StoreLevelClient =
Guice.createInjector(ServiceModule()).getInstance(StoreLevelClient::class.java)
And made a module file for the StoreLevelClient like below:
class ServiceModule : AbstractModule() {
#Provides
#Singleton
fun getClient(myServiceClient : KasServiceClient): StoreLevelClient {
return StoreLevelClient(myServiceClient, AppConfigObject.trackedDocument, AppConfigObject.appConfigFallback)
}
It gave me errors:
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:
3
2022-05-20T18:27:50.800-07:00
1) No implementation for com.kasservice.KasServiceClient was bound.
4
2022-05-20T18:27:50.800-07:00
while locating com.kasservice.KasServiceClient
5
2022-05-20T18:27:50.800-07:00
for the 1st parameter of com.myservice.dependency.ServiceModule.getClient
The KasServiceClient is also from other's
So I #Provides it in the ServiceModule as well:
#Provides
#Singleton
fun getService(
cloudAuthCredentialVisitor: CloudAuthDefaultCredentialsVisitor,
metricsAwareCallVisitor: MetricsAwareCallVisitor,
#Named(BINGBONG_SERVICE_CLIENT_RETRY_STRATEGY)
retryStrategy: RetryStrategy<*>
): KasServiceClient {
val domain = AppConfig.findString(DOMAIN)
val realm = AppConfig.getRealm().name()
val qualifier = "$domain.$realm"
return ClientBuilder()
.remoteOf(KasServiceClient::class.java)
.withConfiguration(qualifier)
.withCallVisitors(cloudAuthCredentialVisitor, metricsAwareCallVisitor, CallAttachmentVisitor(Calls.retry(retryStrategy)))
.newClient()
}
But it gave me errors like below:
Could not find a suitable constructor in com.amazon.coral.client.cloudauth.CloudAuthDefaultCredentialsVisitor. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
Could not find a suitable constructor in com.amazon.metrics.declarative.client.MetricsAwareCallVisitor. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private.
The CloudAuthDefaultCredentialsVisitor and MetricsAwareCallVisitor are use #Provides and instantiate already.
So I don't know why guice can't find them...??
Any idea for this?? I wonder I have some mistake when using Guice. But I have hard time to debug and find

Solved the problem by changing the way of inject:
Instead use:
class ClientAccessor {
companion object {
private val LOGGER = KotlinLogging.logger { }
}
private val myStoreLevelClient: StoreLevelClient =
Guice.createInjector(ServiceModule()).getInstance(StoreLevelClient::class.java)
Tried this:
class ClientAccessor #Inject constructor(private val myStoreLevelClient: StoreLevelClient){
companion object {
private val LOGGER = KotlinLogging.logger { }
}
Reason:
use #Inject instead of using the createInjector manually on particular modules, let guice inject it for us. When I tried to directly use createInjector in instantiating in my code, it will only lookup the specified module and not able to load other modules.

Related

Dagger - Register class without #Inject with minimal ceremony

Lets say I want to register a class with Dagger that doesn't have the #Inject annotation on the constructor and that also takes dependencies in its constructor.
i.e.
// Java
class MyClass {
public MyClass(MyDependency dependency) { ... }
}
// Kotlin
class MyClass(private val dependency: MyDependency) { ... }
Is there a way to register this class without having to manually wire the dependencies into the constructor?
// This is how I currently do it. I must list all constructor dependencies
// and then pass them through to the constructor by hand
#Provides
public MyClass getMyClass(MyDependency depdencency) {
return new MyClass(dependency);
}
// Something like this is how I'd like to do it
// In this case, the class is registered _as if_ it had the #Inject on the constructor
#ProvideEvenWithoutAnInject
public abstract MyClass getMyClass();
Does Dagger offer something like the #ProvideEvenWithoutAnInject annotation shown above?
If you can't put an #Inject annotation on the constructor then Dagger can't create the object for you. You'll need to use a #Provides annotated method with a module or #BindsInstance with your component to add it. (Or as a component dependency from a provision method if you want more extra steps)

How to have a class which can only be instantiated by another specific class

I want to have a class that can only be instantiated by another class. I know I have to make the constructor private otherwise everyone can instantiate it.
class Root private constructor() {
}
class RootMaker: Application() {
fun createRoot() = Root()
} // but this doesn't work because Root's constructor is private
one workaround is to make the maker class, the inner class of the Root class.
class Root private constructor() {
class RootMaker: Application() {
fun createRoot() = Root()
}
}
but I really don't want to do this because the maker class is my application class in android. so what is the better way?
If you want only one instance of an object you can use object keyword in Kotlin. It implements Singleton pattern:
class App : Application {
val root = Root
}
object Root {
fun createObject(): Any {}
}
Now we can access to one instance of Root class either by a property in App class or via Root class: Root.createObject()
UPDATE:
To implement a singleton that only one specific class has access to, we can use an interface and hide its implementation in that specific class (the maker class):
interface IRoot {
// ... methods of creation different objects for dependency injection
}
class App : Application {
val root: IRoot = Root
// hide implementation of `IRoot` interface in `App` class
private object Root : IRoot {
// ... implementation of methods of creation different objects for dependency injection
}
}

Can not call a static panache method in kotlin

First Post. Absolute Beginner. Be kind
I am playing arround with quarkus and kotlin.
I have this kotlin entity class:
#Entity
data class Fruit (
var name: String = "",
var description: String = ""
) : PanacheEntity()
I have this Resource Class based on tutorials in Java:
#Path("/fruits")
#ApplicationScoped
public class FruitJResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Fruit> getAll() {
return Fruit.listAll();
}
}
Everything fine here, Fruit inherits from PanacheEntityBase, i can access listAll()
However,
Same Class in Kotlin does not:
#Path("/fruits")
#ApplicationScoped
class FruitResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
fun getAll(): List<Fruit> = Fruit.listAll()
}
Now i learned allready, that this is probably due kotlin not beeing able to inherit static methods from Super Class.
I read, that i should call the static method direct from the superclass, but this won't work here.
So I need a suggestion for a possible workaround.
The only solution for kotlin and scala languages for now (1.4.1) is to use the Repository pattern :
see documentation: https://quarkus.io/guides/hibernate-orm-panache#solution-2-using-the-repository-pattern
This is due to referenced issue github.com/quarkusio/quarkus/issues/4394.
So if using Kotlin, you simply have to define a new FruitRepository
#ApplicationScoped
class FruitRepository: PanacheRepository<Fruit> {
fun all(): List<Fruit> = findAll(Sort.by("name")).list<Fruit>()
}
Quarkus has released an extension which brings Kotlin support to panache (I think it is still in preview).
in Gradle (if you're using Gradle for your project) you'll need to add the dependencie implementation 'io.quarkus:quarkus-hibernate-orm-panache-kotlin'
To define your "static" methods (Kotlin uses Companion objects to do stuff with static methods) you'll need to define a companion object like this:
#Entity
open class Category : PanacheEntityBase {
#Id
#GeneratedValue
lateinit var id: UUID
// ...
companion object : PanacheCompanion<Category, UUID> {
fun findByName(name: String) = find("name", name).firstResult()
fun findActive() = list("active", true)
fun deleteInactive() = delete("active", false)
}
}
for more information you can check out the official docs:
https://quarkus.io/guides/hibernate-orm-panache-kotlin
Be warned if you use unit tests: at least for me the panache-mock extension is not working with the kotlin version of panache.

Dagger 2, How to add interface in dependency

I just started working with dagger 2. I have created dependency graph for application level dependency. Now that i wanted to create dependency that are required for a specific activity So i created another Component for activity then i created the Module and scope for that component. Now that when i am done writing all the code i build the project but i get compiler error which i am unable to solve.
Here is what i am doing.
#FeedsCatalogActivityScope
#Component(modules = FeedsCatalogActivityModule.class, dependencies = FeederApplicationComponent.class)
//My activity requires Catalog adapter so i am creating dependency for that
public interface FeedsCatalogActivityComponent {
CatalogAdapter getCatalogAdapter();
}
Here is the Module
#Module
public class FeedsCatalogActivityModule {
private final SelectedInterfaceListener selectedInterfaceListener;
public FeedsCatalogActivityModule(SelectedInterfaceListener selectedInterfaceListener) {
this.selectedInterfaceListener = selectedInterfaceListener;
}
#Provides
#FeedsCatalogActivityScope
public CatalogAdapter catalogAdapter(Picasso picasso, SelectedInterfaceListener mSelectesInterfaceListener) {
return new CatalogAdapter(picasso, mSelectesInterfaceListener);
}
}
Here is the scope
#Scope
public #interface FeedsCatalogActivityScope {
}
So now when i build i get this error
/Users/Zeeshan/Desktop/personal/Feeder/app/src/main/java/io/droidninja/feeder/FeederApplication.java
Error:(10, 31) error: cannot find symbol class DaggerFeederApplicationComponent
/Users/Zeeshan/Desktop/personal/Feeder/app/src/main/java/io/droidninja/feeder/ui/activities/FeedsCatalogActivityComponent.java
Error:(13, 20) error: io.droidninja.feeder.ui.adapters.SelectedInterfaceListener cannot be provided without an #Provides-annotated method.
io.droidninja.feeder.ui.adapters.SelectedInterfaceListener is injected at
io.droidninja.feeder.ui.activities.FeedsCatalogActivityModule.catalogAdapter(…, mSelectesInterfaceListener)
io.droidninja.feeder.ui.adapters.CatalogAdapter is provided at
io.droidninja.feeder.ui.activities.FeedsCatalogActivityComponent.getCatalogAdapter()
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
Compilation failed; see the compiler error output for details.
What i am understanding is that i have problem in FeedsCatalogActivityModule. How should i provide SelectedInterfaceListener? It is a interface.
P.S i am new to dagger2 i just get started with it.
According to your code, you are suppose to pass an instance of SelectedInterfaceListener to FeedsCatalogActivityModule when your are building FeedsCatalogActivityComponent inside the activity that uses it.
in your activity create a method that setup the component like this
private void initializeInjector() {
FeedsCatalogActivityComponent feedsCatalogActivityComponent = DaggerFeedsCatalogActivityComponent.builder()
.feederApplicationComponent(feederApplicationComponent()/* create this method and it should return a correctly built FeederApplicationComponent */ )
.feedsCatalogActivityModule(
new FeedsCatalogActivityModule(
new SelectedInterfaceListener()
/* pass in the instance of SelectedInterfaceListener here */ )
).build();
}
And then remember to change the Module provides method to
#Provides
#FeedsCatalogActivityScope
public CatalogAdapter catalogAdapter(Picasso picassor) {
return new CatalogAdapter(picasso, this.selectedInterfaceListener);
}
Well, you must somehow provide an implementation for that interface. Take a look at:
#Binds
#Provides
Binds vs. Provides
Example
#Binds
abstract SelectedInterfaceListener provideDsListPresenter(SelectedInterfaceListenerImpl impl);

No implementation was bound - Java Guice

Novice here trying to use a dummy Java Facebook app that uses Guice to inject a database dependency into the Facebook factory but continue to have Guice error out telling me:
### No implementation for com.example.storage.Db annotated with #com.example.storage.annotations.SystemDb() was bound while locating com.example.storage.Db annotated with #com.example.storage.annotations.SystemDb() for parameter 0 at com.example.facebook.client.exceptions.FacebookExceptionHandlerDb at com.example.facebook.client.guice.FacebookClientModule.configure
### Could not find a suitable constructor in com.example.facebook.statsd.StatsdClient. Classes must have either one (and only one) constructor annotated with #Inject or a zero-argument constructor that is not private. at com.example.facebook.statsd.StatsdClient.class while locating com.example.facebook.statsd.StatsdClient for parameter 1 at com.example.facebook.client.exceptions.FacebookExceptionHandlerDb. com.example.facebook.client.guice.FacebookClientModule.configure
Code for app:
app.java
package com.example.facebook;
import com.google.inject.Guice;
import com.restfb.Connection;
import com.restfb.types.Post;
import com.example.facebook.client.FacebookClientFactory;
import com.example.facebook.client.RobustFacebookClient;
import com.example.facebook.client.guice.FacebookClientModule;
import com.example.facebook.statsd.StatsdClient;
public class App {
public static void main ( String[] args ) {
final FacebookClientFactory facebookClientFactory =
Guice.createInjector(new FacebookClientModule()).getInstance(FacebookClientFactory.class);
//error from line above
final RobustFacebookClient robustFacebookClient =
facebookClientFactory.create("accessToken");
//more ...
}
The resulting error points me to the FacebookClientModule binding:
FacebookClientModule.java
public class FacebookClientModule extends AbstractModule {
bind(FacebookExceptionHandler.class).to(FacebookExceptionHandlerDb.class);
//error resulting from the failed binding on the FacebookExceptionHandlerDB class
install(new FactoryModuleBuilder()
.implement(FacebookClient.class, RobustFacebookClient.class)
.build(FacebookClientFactory.class));
}
}
Where inside the FacebookExceptionHandleDB class the constructor has the injection:
FacebookExceptionHandlerDB.java
public class FacebookExceptionHandlerDb implements FacebookExceptionHandler {
// list of class String variables ...
private final FacebookErrorParser parser;
private final Db db;
private StatsdClient statsd;
#Inject
public FacebookExceptionHandlerDb(#SystemDb Db db, StatsdClient statsd, FacebookErrorParser parser) {
this.db = db;
this.statsd = statsd;
this.parser = parser;
}
}
From what I can gleam, the dependency injection for parameters zero and one, db and statsD respectively, is failing. Could someone point out where or what in the app code is missing?
At first glance it seems like your missing the bindings for the Db annotated dependency and the StatsdClient.
You'll need to provide the missing bindings to your module like so
bind(Db.class).annotatedWith(SystemDb.class).to(DbImplOfSomeSort.class);
bind(StatsdClient.class).to(StatsdClientImplOfSomeSort.class);
Guice is able to automatically inject Concrete Class with either a public no argument constructor or a constructor with #Inject without any specific defined binding in your module but when it comes to Interfaces you have to define the necessary bindings.
Here Db.class and StatsdClient.class are interfaces which you need to bind to specific implementation.
Not the source of the issue in this particular case, but I ran across this issue when I had my implementation and interface classes backwards:
public class MyModule extends AbstractModule {
#Override
public void configure() {
bind(MyClassImpl.class).to(MyInterface.class);
}
}
Should have been:
bind(MyInterface.class).to(MyClassImpl.class);

Categories

Resources