Dagger Issue - Generate useCase has error - java

i created my useCase and setup input and output and then provide it on module and everything works fine.
class GetProfileUseCase constructor(
private val repository: Repository,
defaultDispatcher: CoroutineDispatcher
) : SuspendUseCase<Request, ResultEntity<Response>>(defaultDispatcher) {
override suspend fun execute(parameters: Request): ResultEntity<Response> {
return repository.getProfile(parameters)
}
}
and here is my data class
sealed class GetProfile : Serializable {
data class Request(
val nothing: Nothing? = null
) : GetProfile()
data class Response(
val user: User? = User()
) : GetProfile()
}
because there is no parameter in Request class i tried changed it to :
object Request
but when build it IDE error :
error: method create in class ViewModel_Factory cannot be applied to given types;
and here is my view model :
class ViewModel #Inject constructor(
private val getProfileUseCase: GetProfileUseCase
) : BaseViewModel()
i don't know why it happen and dagger couldn't generate classes !!!
it works without no error when set Request as data class but crash when make it object class

because there is no parameter in Request class i tried changed it to :
object Request
You seem to think an object is same as a class with a single no parameter constructor, which is not true. For complete understanding I encourage you to read this thread.
However I will try to provide a brief explanation as to why your code doesn't work
When you do object Request, it makes Request a singleton, meaning you can no longer create its instances using val instance = Request(), reason being that constructor of Request is marked private by kotlin compiler.
so when your code(dagger) tries to inject Request using new Request(), it gives you error.

Related

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

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.

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.

"Accidental override: The following declarations have the same JVM signature" when implementing Java interface

I faced the following error trying to extend RuntimeException and implement GraphQLError interface, defined in Java, from my Kotlin code. This is the error:
Accidental override: The following declarations have the same JVM signature (getMessage()Ljava.lang.string;):
public open fun <get-message>(): String? defined in NegativeCountException
public open fun getMessage(): String? defined in NegativeCountException
The following is my code:
class NegativeCountException() : RuntimeException(), GraphQLError {
override fun getMessage(): String? {
TODO("not implemented")
}
<...>
}
where GraphQLError is an interface, defined in Java as shown bellow:
public interface GraphQLError {
String getMessage();
<...>
}
Seems like it clashes with getMessage() defined in Throwable.
I can't change code of the interface, because it comes from a library.
How can I create my own runtime exception, that will implement GraphQLError?
PS: I also tried the following, and received a very similar error:
class NegativeCountException(override val message: String?) : RuntimeException(), GraphQLError {
<...>
}
This is a graphql problem. My workaround:
Reimplement GraphQLError, ExceptionWhileDataFetching and DataFetcherErrorHandler.
KGraphQLError is a "fixed" kotlin interface (with val instead of getters) that you use for your custom errors.
in KDataFetcherErrorHandler: Replace ExceptionWhileDataFetching in this line with KExceptionWhileDataFetching:
val error = ExceptionWhileDataFetching(path, exception, sourceLocation)
KExceptionWhileErrorHandling implements GraphQLError. Look through the code and replace all instances of if (exception is GraphQLError) with (exception is KGraphQLError)
Pass the new KDataFetcherErrorHandler to your queryExecutionStrategy and mutationExecutionStrategy.
Your custom errors can now extend Throwable and implement KGraphQLError, and get handled properly.
More info here: http://graphql-java.readthedocs.io/en/latest/execution.html
I think it would work, when message was not a field in the one class (Throwable) and a method in the other. But it seems kotlin can not resolve the ambiguity when message is a field in the class and a method in the interface. If you have control over your GraphQlError you could do this:
class NegativeCountException() : RuntimeException(), GraphQLError {
override val message: String?
get() = super.message
}
interface GraphQLError {
val message: String?
}
This is because Kotlin will create getters and setters for your variables when generating Java byte code. For example,
class Foo(val bar)
Foo with have getBar in Java byte code. To avoid name conflict, use #JvmField and #JvmName.
Read more about this here.
There is a quick and dirty workaround, in case your project allows Java alongside Kolin.
Write your NegativeCountException in Java :D
There's actually a good solution for this (provided here):
class NegativeCountException(#JvmField override val message: String) : RuntimeException(message), GraphQLError {
override fun getMessage(): String? = super.message
<...>
}

RESTlet Authorization Filter

I am developing a RESTlet API (JAVA), and I've created a custom authorization filter that I run all requests through before passing it to my router. In my requests I always pass the session ID as a request attribute, e.g.
http://localhost:8080/myAPI/{sid}/someResource/
Now, in my functions that extends ServerResource, I can do something like this to easily extract that {sid}:
String sid = (getRequestAttributes().containsKey("sid")) ? getRequestAttributes().get("sid").toString() : "";
My problem is, in my authorization function, which extends Filter (the authorization function is not called via a router, but is called in my main createInboundRoot() function), I cannot use the same method to extract the {sid}. I've created a workaround using string manipulation of request.getResourceRef().getSegments(), but there must be a better way?
Any help will be appreciated!
Thanks
You can create a common parent class for any child of ServerResource. like this:
public class CommonParentResource extends ServerResource
{
// class definition
}
And then override the doInit() method of the ServerResource class in it.
public class CommonParentResource extends ServerResource
{
public void doInit()
{
boolean authorized=false;
String sid = getRequestAttributes().containsKey("sid") ? (String)getRequestAttributes().get("sid") : StringUtils.EMPTY;
// Authorization logic here.
if(!authorized)//after authorization process completed.
{
getResponse().setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
getResponse().setEntity(/*Representation carrrying message for unauthorized user*/);
}
}
}
Now any new child class of ServerResource that you want to perform this authorization check, must extend this CommonParentResource class. Like this:
public class FriendsListResource extends CommonParentResource
{
#Get
//......
}
Two points are important here:
doInit() of any child class of ServerResource is called before calling any method annotated with #Get / #Post / ...
(Caution) If you do not use this statement:
getResponse().setStatus(Status.CLIENT_ERROR_UNAUTHORIZED);
i.e. if you do not set status of response to an error, then methods annotated with #Get / #Post / #Put / ... will get called ! But if your program sets the status of the response to an error-status, then the #Get / #Post / #Put / ... will not get executed, and the end user will see the error message represented by:
getResponse().setEntity(/*Representation carrrying message for unauthorized user*/);

Is it possible to have strongly typed HTTP request handlers in Restlet?

Consider the following ServerResource derived type:
public class UserResource extends ServerResource {
#Get
public User getUser(int id) {
return new User(id, "Mark", "Kharitonov");
}
}
(Yes, it always returns the same user no matter the given id).
Is it possible to make it work in Restlet? Because, as far as I understand, the expected signature of the GET handler is:
Representation get();
OR
Representation get(Variant v); // (no idea what it means yet)
Now I understand, that I can implement the non type safe GET handler to extract the arguments from the request and then invoke getUser, after which to compose the respective Representation instance from the result and return. But this is a boilerplate code, it does not belong with the application code, its place is inside the framework. At least, this is how it is done by OpenRasta - the REST framework I have been using in .NET
Thanks.
You should remove the parameter from the signature
#Get
public User getUser() {
String id = getQuery().getFirstValue("id");
return new User(id, "Mark", "Kharitonov");
}
No need to override the get() methods in this case as the #Get annotation will be automatically detected.

Categories

Resources