I'm trying to create an abstract class with generic parameter which will have subclasses which should call methods without having to specify type parameters. I have this so far:
abstract class AbstractClass<T : Any> @Autowired constructor(protected val delegate: MyService) {
inline fun <T: Any> myMethod(param: Any): T? {
return delegate.myMethod(param).`as`(T::class.java)
}
}
And implementation:
class TesterWork @Autowired constructor(delegate: MyService) : AbstractClass<Tester>(delegate) {
}
Now when calling myMethod
I have to specify the type argument:
testerWork.myMethod<Tester>("test")
I was wondering would it be possible to infer the type argument automatically?
Can I somehow rework myMethod? Note that I need to have T::class.java
inside the method.
You cannot use a class' generic parameter as a reified generic (getting its T::class
token), because at runtime the generic parameter is erased: Kotlin follows Java's type erasure practice and doesn't have reified generics for classes.
(Kotlin has reified generics only for inline functions)
Given that, it's up to you to pass and store a Class<T>
token so that you can use it.
Also, myFunction
in your example introduces a generic parameter, and it will be a new generic, not connected to the class generic parameter in any way (naming both T
only adds confusion, consider them T1
and T2
). If I get it right, you meant the class' generic instead.
Probably what you can do is declare an abstract val
that would store a class token and rewrite the function so that it uses the stored class token:
abstract class AbstractClass<T : Any> constructor(protected val delegate: MyService) {
protected abstract val classToken: Class<T>
fun myMethod(param: Any): T? {
return delegate.myMethod(param).`as`(classToken)
}
}
Then, deriving from AbstractClass
will require overriding the classToken
:
class TesterWork constructor(delegate: MyService) : AbstractClass<Tester>(delegate) {
override val classToken = Tester::class.java
}
After that, you will be able to call the function on TesterWork
instance without specifying the generic parameter:
val service: MyService = ...
val t: Tester? = TesterWork(service).myMethod("test")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With