Can a abstract class include non-abstract class parameter in Kotlin? - kotlin

The Code A is from the aritcle https://developer.android.com/training/dependency-injection/hilt-android
In my mind, a abstract class can not include non-abstract class .
But the function abstract fun bindAnalyticsService( analyticsServiceImpl: AnalyticsServiceImpl): AnalyticsService accept a non-abstract class parameter, why?
Code A
interface AnalyticsService {
fun analyticsMethods()
}
// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl #Inject constructor(
...
) : AnalyticsService { ... }
#Module
#InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {
#Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}

Related

Kotlin concrete class extending from abstract class and interface, with the interface using a method implemented in the abstract class

I want to ask a question that I have some clues about, but I don't want to influence the answers I will get. I have the following class hierarchy:
abstract class MyAbstractClass {
fun displayStuff(id: String) {
println("My id is $id.")
}
}
interface MyInterface {
fun displayThis() {
displayStuff("some-value")
}
fun displayStuff(id: String) // Not implemented here
}
class MyConcreteClass(): MyAbstractClass(), MyInterface {
fun doStuff() {
displayThis()
}
}
fun main() {
val result = MyConcreteClass()
result.doStuff()
result.displayStuff("id")
}
What's wrong with this design, and how do you suggest I fix it?
It would probably not be a bad idea to extract the displayStuff into another interface. Then MyAbstractClass and MyInterface can both derive from the same interface.
One overrides the displayStuff function, hence providing something like an abstract base implementation for the interface.
The other one is using the function in a specific way, thereby extending the functionality of the interface.
interface DisplayStuff {
fun displayStuff(id: String)
}
abstract class MyAbstractClass: DisplayStuff {
override fun displayStuff(id: String) = println("My id is $id.")
}
interface MyInterface : DisplayStuff {
fun displayThis() = displayStuff("some-value")
}

Ensure KClass of class that implements interface

I have a custom converter annotation like:
#Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
#Retention(AnnotationRetention.RUNTIME)
#MustBeDocumented
annotation class CustomConverter(val converter: KClass<*>)
And I have an interface:
interface FooConverter<T> {
fun from(str: String): T?
fun to(value: T): String
}
And I have a class implementing this interface:
class BarConverter : FooConverter<Int> {
// Implementation
}
And I use the annotation like:
class MyDTO {
#CustomConverter(BarConverter::class)
var myProp: Int? = null
}
Is there a way to ensure the KClass on the annotation has a class that implements the FooConverter<T> interface?
I have tried:
annotation class CustomConverter(val converter: KClass<FooConverter<*>>)
annotation class CustomConverter(val converter: KClass<FooConverter<Any>>)
but it doesn't work. The compiler complains.
Thanks!

Dagger #Provides in Kotlin

I'm trying to understand Dagger. I created applicationInjector class :
class BaseApplication : DaggerApplication() {
override fun applicationInjector(): AndroidInjector<out DaggerApplication>? {
return DaggerAppComponent.builder().application(this)?.build()
}
}
And here's my AppComponent
#Component(
modules = [AndroidSupportInjectionModule::class,
ActivityBuilderModules::class]
)
interface AppComponent : AndroidInjector<BaseApplication> {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application?): Builder?
fun build(): AppComponent?
}
}
Now what I want to do is to to inject simple String to Activity (really basic, right ?)
In Java it works like this :
#Module
abstract class ActivityBuilderModules {
#ContributesAndroidInjector
abstract fun contributeAuthActivity() : AuthActivity
//JAVA
#Provides
public static String provideTestString() {
return "TEST "
}
however we don't have static function in Kotlin, right ? And it needs to be static cause I'm getting an error :
error: com.example.kotlintests.di.ActivityBuilderModules is abstract and has instance #Provides methods. Consider making the methods static or including a non-abstract subclass of the module instead.
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.example.kotlintests.BaseApplication> {
I tried with package level function but it didn't work. How can I add provideTestString function in Kotlin ?

Kotlin abstract class must have constructor and get initialized

When I have this class hierarchy:
SUPERCLASS
abstract class AbsSuperClass {
abstract fun someFun()
}
SUBCLASS
class Subclass : AbsSuperClass {
override fun someFun()
}
I get an IDE error in the subclass saying:
This type has a constructor, and thus must be initialized here
But doesnt this counter the whole argument of having abstract classes? I just DONT want the abstract class to be initialized
You have just forgotten () in your class extension:
class Subclass : AbsSuperClass() {
override fun someFun()
}

Class is not abstract and does not implement abstract base class member

I'm confused by this Kotlin error associated with providing an implementation for an abstract class that has been imported from a maven package.
I have a maven library that is written in Kotlin and exposes an abstract class called APIGatewayRequestHandler. In my app that imports the library, I provide an implementation of the abstract class:
class GetWelcomeMessageHandler : APIGatewayRequestHandler<WelcomeMessage>()
fun handleAPIGatewayRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, context: com.amazonaws.services.lambda.runtime.Context?): WelcomeMessage {
return WelcomeMessage()
}
}
The decompiled abstract class from the library looks like this:
public abstract class APIGatewayRequestHandler<T> public constructor() : com.amazonaws.services.lambda.runtime.RequestHandler<com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, T> {
public abstract fun handleAPIGatewayRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, context: com.amazonaws.services.lambda.runtime.Context?): T
public open fun handleRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent?, context: com.amazonaws.services.lambda.runtime.Context?): T {
/* compiled code */
}
}
I get the following error:
Class 'GetWelcomeMessageHandler' is not abstract and does not implement abstract base class member
public abstract fun handleAPIGatewayRequest(input: APIGatewayProxyRequestEvent, context: Context?): WelcomeMessage
I think you're just missing some override keywords. Namely, your abstract class should have it on the handleRequest method:
public abstract class APIGatewayRequestHandler<T> public constructor() : com.amazonaws.services.lambda.runtime.RequestHandler<com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, T> {
public abstract fun handleAPIGatewayRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, context: com.amazonaws.services.lambda.runtime.Context?): T
public override fun handleRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent?, context: com.amazonaws.services.lambda.runtime.Context?): T {
/* compiled code */
}
}
And then your GetWelcomeMessageHandler should have it on its handleAPIGatewayRequest method:
class GetWelcomeMessageHandler : APIGatewayRequestHandler<WelcomeMessage>() { // <-- This curly brace was also missing
override fun handleAPIGatewayRequest(input: com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent, context: com.amazonaws.services.lambda.runtime.Context?): WelcomeMessage {
return WelcomeMessage()
}
}

Categories