Consider an abstract class:
abstract class PubSubSubscriber<T : Any>(private val topic: KClass<T>) : BackgroundFunction<PubSubMessage> {
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
}
And implementation:
class MySubscriber : PubSubSubscriber<Payload>(Payload::class) {
Is there a way to define such abstract class so that I don't have to repeat twice the Payload and Payload::class in the class definition?
Yes, with some reflection.
At construction time, we can extract the type parameter and assign it to a property that no longer needs to be given to the constructor:
abstract class PubSubSubscriber<T : Any> {
val topic: KClass<T> = extractTypeParam<T>(0).kotlin
private fun <X> extractTypeParam(paramIdx: Int): Class<X> {
require(PubSubSubscriber::class.java == javaClass.superclass) {
"PubSubSubscriber subclass $javaClass should directly extend PubSubSubscriber"
}
#Suppress("UNCHECKED_CAST")
return (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[paramIdx] as Class<X>
}
abstract fun consume(payload: T)
override fun accept(message: PubSubMessage, context: Context) {
val json = String(Base64.getDecoder().decode(message.data.toByteArray()))
val payload = objectMapper.readValue(json, topic.java)
consume(payload)
}
Note the following limitations:
A) this solution works only if MySubscriber directly extends from PubSubSubscriber. However, the given code can detect if that's not the case and warn about it (at runtime). In such cases, there are the following solutions:
MySubscriber falls back to providing a duplicate argument (essentially what you already had)
the direct superclass of MySubscriber can provide a similar detection mechanism
B) You call reflection code every time a MySubscriber instance is created. This may be too slow in certain contexts, but for many this is unproblematic.
Related
I have a base class:
abstract class JSONDeserializationStrategy<T : Any>: DeserializationStrategy<T> {
protected abstract fun parse(json: JsonObject): T
protected abstract fun getSerializationException(): SerializationException
}
and then a derived class
class MyClassParserDeserializationStrategy : JSONDeserializationStrategy<MyClass>() {
override val descriptor: SerialDescriptor
= buildClassSerialDescriptor("MyClass")
override fun getSerializationException(): SerializationException
= throw SerializationException("Invalid JSON received for MyClass.")
How could I move the property descriptor and the method getSerializationException from the derived class into the base class, since they only "adapt" by providing their name as String? I was trying to do something in the direction of T::class.java.simpleName as String but it didnt work. What is the best way to do this?
As #Tenfour04 explained, T is erased, so it is not directly accessible. However, as long as the subclass of JSONDeserializationStrategy provides the T as a specific class/type, it can be acquired with a bit of reflection voodoo:
fun main() {
val strategy = MyClassParserDeserializationStrategy()
println(strategy.descriptor.serialName) // MyClass
}
abstract class JSONDeserializationStrategy<T : Any>: DeserializationStrategy<T> {
protected val type: KType = this::class.supertypes
.first { it.classifier == JSONDeserializationStrategy::class }
.arguments[0].type!!
#Suppress("UNCHECKED_CAST")
protected val typeClass = requireNotNull(type.classifier as? KClass<T>) {
"T is unknown"
}
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(typeClass.simpleName!!)
fun getSerializationException(): SerializationException =
throw SerializationException("Invalid JSON received for ${typeClass.simpleName!!}.")
...
}
I'm not 100% sure, but I believe both type!! and simpleName!! are safe, they can't be null.
Also, it won't work if T is really fully erased and unknown, e.g.:
val strategy = GenericParserDeserializationStrategy<MyClass>() // exception
For this reason it makes sense to open type/typeClass properties for overriding, so generic non-abstract subclasses could provide their own means to acquire T. However, then we would probably need to move the initialization of most of properties outside of the constructor.
Because of type erasure, T's class is not accessible. Work-around could be to add it as a constructor property that returns the type, and then the subclasses must pass the type. The property needs to be in the constructor, rather than provided as an abstract property for subclasses to override because you need it to initialize descriptor at instantiation time. (It's highly discouraged to call an open property at class initialization time.)
abstract class JSONDeserializationStrategy<T : Any>(protected val typeClass: KClass<out T>): DeserializationStrategy<T> {
protected abstract fun parse(json: JsonObject): T
override val descriptor: SerialDescriptor = buildClassSerialDescriptor(typeClass.simpleName!!)
fun getSerializationException(): SerializationException =
throw SerializationException("Invalid JSON received for ${typeClass.simpleName}.")
}
class TodaySaleParserDeserializationStrategy : JSONDeserializationStrategy<TodaySale>(TodaySale::class) {
}
Im new to Kotlin and investigating what is/isnt possible
I have a use case as follows:-
As a technical exercise I am attempting to model remote API requests and responses, and enforce relationships between them
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
Pseudo code:-
Requests {
Request1 -> Response1
Request2 -> Response2
...
RequestN -> ResponseN
}
I have defined two interfaces Request & Response and employ them as follows:-
interface Request {
fun <T> response(data : T): Lazy<Response>
}
interface Response
data class Request1(val request: String) : Request {
data class Response1(val output: String) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response1(data as String) }
}
}
data class Request2(val request: Long) : Request {
data class Response2(val output: Double) : Response
override fun <T> response(data: T): Lazy<Response> {
return lazy { Response2(data as Double) }
}
}
I have a Controller class that makes the API calls as follows:-
class Controller {
fun call(request: Request): Lazy<Response> {
return when (request) {
is Request1 -> request.response("Testing Data")
is Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
Using the above data classes I can enforce that Request1 is linked to only Response1 and also specify the response data type wrapped by each Response.
Although the above classes provide the functionality and adhere to these rules, they are verbose.
Is there a more succinct approach I could employ to obtain the desired result.
The reason I require this is I am looking for "Self Documenting" code, where a developer can view the definition of Request/Response pairs and association rules and clearly see what is intended.
For example: A developer looking at the final Request definitions can clearly see that Response1 with be generated by Request1. I also want to enforce that Response1 can only ever be produced from Request1.
My example above is simplified, as in "The Real World" the data wrapped by each Response will be sourced from the actual API request call, I have illustrated with "Hard Coded".
I would much rather define Request1 and Response1 on a single line if possible.
UPDATE
I have refactored my original classes as follows:-
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
override fun response(data: String): Lazy<Response> {
return lazy { Response1(data) }
}
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
override fun response(data: Double): Lazy<Response> {
return lazy { Response2(data) }
}
}
}
class Controller {
fun <T> call(request: Request<T>): Lazy<Response> {
return when (request) {
is Requests.Request1 -> request.response("Testing Data")
is Requests.Request2 -> request.response(Math.PI)
else -> TODO()
}
}
}
While this version of my code has many benefits from the original, one feature I am still not happy with is that each Request/Response declaration is still quite verbose, e.g. it requires 5 lines of code. Is there an approach I can employ to make each Request/Response pair declaration more succinct?, e.g. take up fewer lines of code.
UPDATE II
Im attempting to refactor my sealed class above so that the overridden function response is defined in the outer sealed class.
interface Request<ResponseData> {
fun response(data: ResponseData): Lazy<Response>
}
interface Response
sealed class Requests<T> : Request<T> {
data class Request1(val request: String) : Requests<String>() {
inner class Response1(val output: String) : Response
}
data class Request2(val request: Long) : Requests<Double>() {
inner class Response2(val output: Double) : Response
}
override fun response(data: T): Lazy<Response> {
return lazy { // What implementation goes here??? // }
}
}
Is this approach possible?
How do I refer to the individual concrete ResponseN classes in the outer sealed class?
Another approach:
data class Box<T, V>(val req: T, val rsp: V)
interface Interaction<RequestT, ResponseT> {
val req: RequestT
fun exec(): Box<RequestT, ResponseT>
}
sealed class Interactions<RequestT, ResponseT> : Interaction<RequestT, ResponseT> {
class Interaction1(override val req: String) : Interaction<String, String> {
override fun exec() = Box(req, "by")
}
class Interaction2(override val req: Long) : Interaction<Long, Double> {
override fun exec() = Box(req, 1.0)
}
}
fun main() {
val interaction1 = Interactions.Interaction1("hi")
val interaction2 = Interactions.Interaction2(42)
println(interaction1.exec()) // Box(req=hi, rsp=by)
println(interaction2.exec()) // Box(req=42, rsp=1.0)
}
Maybe your example is simplified from what you're actually doing, but I don't see the purpose of the Response interface, or the need for separate Request implementations to achieve what your code does:
data class Request<T>(val request: String, val responseType: KClass<out T>) {
fun response(data : T) = lazy { data }
}
class Controller {
fun <T: Any> call(request: Request<T>): Lazy<T> {
#Suppress("UNCHECKED_CAST")
return when (request.responseType) {
String::class -> request.response("Testing Data" as T)
Double::class -> request.response(Math.PI as T)
else -> TODO()
}
}
}
It's kind of an odd use of Lazy though, since you are wrapping a pre-computed value.
My goal is to be able to declare the relationship between Requests and Responses in a clear and succinct way at the top of a Class. This will 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1
A great way to enforce the relationships is to separate the interface and implementation levels. Currently you have your interface defined as
interface Request {
fun <T> response(data : T): Lazy<Response>
}
And it does not tell you that the response can vary. It's high level and then you define actual relations in your implementation.
I suggest to decouple relations and the implementation by moving the relations to the interface level.
Here is my suggestion. Forgive me if something does not compile, I'm writing the code from my head, I want to communicate the design ideas and you may have to change some pseudocode.
Let's start with the interface:
interface Response
interface Request // I see that you are using primitive types for requests, so you don't need the interface. But in a real world scenario your requests will probably be more complex than primitive types and then it will make sense to wrap them in this interface. It also makes the code easier to understand - a string can be anything, while a Request is definitely a request.
// This is an interface that actually performs a request, so makes sense to name it in an actionable way
interface Requester<T, M> {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
This declaration tells you that there are different kinds of requests and responses and that there are some relations, but do not say what relations are yet.
Then I would declare the responses and requests implementations in a separate place to keep this code short and to the point
class Request1(val input: String) : Request
class Request2(val input: Double) : Request
class Response1(val output: String) : Response
class Response2(val output: Double) : Response
Then you declare the actual relations
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
At this point you have a file that clearly communicates the relation without any implementation details.
This is you final interface code, that solves your request for 1). document the API calls made by this Class, 2). Enforce the relationship so that Request1 can only produce Response1 ⬇️
interface Response
interface Request
interface Requester {
fun <in T: Request, out M: Response> request(data : T): Lazy<M>
}
interface Requester1: Requester<Request1, Response1>
interface Requester2: Requester<Request2, Response2>
Then you can do the implementation in a separate place to keep the interface clean and easy to understand.
sealed class Requests {
data class RequesterImpl1(val request: String) : Requests, Requester1 {
override fun request(data: Request1): Lazy<Response1> {
return lazy { Response1(data) }
}
}
data class RequesterImpl2(val request: Long) : Requests, Requester2 {
override fun request(data: Double2): Lazy<Response2> {
return lazy { Response2(data) }
}
}
}
This is the current design I am using
fun doNothing(): Unit = Unit
interface Interaction<Input, Output> {
interface Response<Output> : Interaction<Unit, Output> {
val output: Output
}
interface Request<Input, Output> : Interaction<Input, Output> {
val input: Input
fun react(output: Output): Response<Output>
}
}
sealed class Interactions<I, O> : Interaction<I, O> {
data class RequestOne(override val input: String) : Interaction.Request<String, Long> {
internal data class ResponseOne(override val output: Long) : Interaction.Response<Long>
override fun react(output: Long): Interaction.Response<Long> = ResponseOne(output)
}
data class RequestTwo(override val input: CustomInput) : Interaction.Request<CustomInput, CustomOutput> {
internal data class ResponseTwo(override val output: CustomOutput) : Interaction.Response<CustomOutput>
override fun react(output: CustomOutput): Interaction.Response<CustomOutput> = ResponseTwo(output)
}
data class RequestThree(override val input: Unit = doNothing()) : Interaction.Request<Unit, CustomOutputTwo> {
internal data class ResponseThree(override val output: CustomOutputTwo) : Interaction.Response<CustomOutputTwo>
override fun react(output: CustomOutputTwo): Interaction.Response<CustomOutputTwo> = ResponseThree(output)
}
data class RequestFour(override val input: Unit = doNothing()) : Interaction.Request<Unit, Unit> {
internal data class ResponseFour(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFour()
}
data class RequestFive(override val input: CustomInputTwo) : Interaction.Request<CustomInputTwo, Unit> {
internal data class ResponseFive(override val output: Unit = doNothing()) : Interaction.Response<Unit>
override fun react(output: Unit): Interaction.Response<Unit> = ResponseFive()
}
}
I believe this approach enforces the relationships I require between individual Requests and their associated Response types.
The features of this design I would like to improve on is the use of Unit when defining the Response interface.
Also I cannot see a way to improve on the sealed class Interactions<I, O> : Interaction<I, O> {...}, as I never use the Generic I & O
I would also like to be able to define a single fun react(output: Output): Response<Output> within the parent sealed class Interactions instead of having to implement this function in each inner Action data class, however I do not think that is possible.
I am trying to create a POJO (aka data classes in Kotlin) structure of a JSON response in Kotlin. I've implemented the Parcelable interface for each data class in the structure. In all of the data classes, I've auto generated the Parcelable implementation. The issue is the generated second constructor where the IDE is complaining about:
Overload resolution ambiguity
It states that it's being confused between these two constructors:
public constructor GeocodeRes(parcel: Parcel)
public constructor GeocodeRes(responset: ResponseRes)
Which I believe makes sense because ResponseRes is also of type Parcelable (ResponseRes implements Parcelable). So calling the GeocodeRes(parcel) method (within the createFromParcel companion method), it is getting confused.
That was until I removed ResponseRes from implementing the Parcelable class and it's still showing the same error.
Is there any reason to this? Am I setting this up properly? In all of the children data classes, they all implement the Parcelable interface (with dependence with eachother) but aren't running into any issues.
Here's my GeocodeRes class:
import android.os.Parcel
import android.os.Parcelable
import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName
data class GeocodeRes(
#SerializedName("Response") #Expose val responset: ResponseRes
) : Parcelable {
// this is the problem. the IDE is complaining that the usage is too ambiguous (). however, the only usage of this constructor is within this class - just doesn't tell me where exactly.
constructor(parcel: Parcel) : this(parcel.readParcelable(ResponseRes::class.java.classLoader)) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeParcelable(responset, flags)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<GeocodeRes> {
override fun createFromParcel(parcel: Parcel): GeocodeRes {
return GeocodeRes(parcel)
}
override fun newArray(size: Int): Array<GeocodeRes?> {
return arrayOfNulls(size)
}
}
}
Here's my ResponseRes class:
data class ResponseRes(
#SerializedName("MetaInfo") #Expose val metaInfo: MetaInfo,
#SerializedName("View") #Expose val views: List<View>
): Parcelable
{
[...]//parcel methods
}
however, the only usage of this constructor is within this class - just doesn't tell me where exactly
The problem is with the definition itself, not with any usage. It could never be used, and the error would still be there.
You should be able to fix this by specifying which Parcelable you want to read:
this(parcel.readParcelable<ResponseRes>(ResponseRes::class.java.classLoader))
The compiler can't decide if you mean that or
this(parcel.readParcelable<Parcel>(ResponseRes::class.java.classLoader))
Even though the second wouldn't be legal because Parcel doesn't implement Parcelable, if you look at the signature
<T extends Parcelable> T readParcelable(ClassLoader loader)
you can see only the return type can be used to infer T, not the argument. So the compiler need to pick the constructor overload before trying to infer T.
I have an abstract stub class that needs to be subclasses to add spring annotations.
abstract class ConsumerStub<TYPE>{
val receivedMessages: MutableMap<String, TYPE> = ConcurrentHashMap()
open fun processMessage(#Payload payload: TYPE, record: ConsumerRecord<String, *>) {
this.receivedMessages[record.key()] = payload
}
fun receivedMessageWithKey(key: String): Boolean = this.receivedMessages.contains(key)
fun receivedMessageWithKeyCallable(key: String): Callable<Boolean> = Callable { receivedMessageWithKey(key) }
fun getReceiveMessageWithKey(key: String): TYPE? = this.receivedMessages[key]
fun reset() {
this.receivedMessages.clear()
}
}
for example:
open class WorkflowRequestConsumerStub: ConsumerStub<InternalWorkflowRequest>() {
#KafkaListener(
id = "xyzRequestConsumerStub",
topics = ["abc-workflow-requests"]
)
override fun processMessage(
#Payload payload: InternalWorkflowRequest,
record: ConsumerRecord<String, *>
) {
super.processMessage(payload, record)
}
}
I am seeing some really weird behaviour with the receivedMessages.
After some debugging I realised there seem to be 2 instances of receivedMessages.
stub.reset() throws a null pointer exception
after changing the code to initialize receivedMessages in reset(), processMessage() and receivedMessageWithKey() are seeing 2 different receivedMessages with different objectIds.
what's going on? In java the subclass should have access to any protected members in the super, so I assume the same applies to kotlin.
UPDATE: this works as expected when defining receivedMessages abstract and override in the implementations. That really sucks if this is how it should be done in kotlin. In this case there is no need for the implementation to care about the map.
I'm currently writing some classes that represent symbolic mathematical expressions. All of these are immutable.
However, I found myself often repeating the same kind of structure, so I created an interface to avoid repetition, but find myself unable to avoid duplicating the "substituteInside" method (see below), which returns a copy of the object with components corresponding to "find" replaced with "replace".
This behavior is the same for all instances of this interface.
In my current solution, the interface requires implementing a method createOp which returns the modified copy of the object.
interface UnarySymbolicOp<InType : Any,
OutType : Any,
OpType : UnarySymbolicOp<InType,OutType,OpType>> :
Symbolic<OutType> {
// Arg may be a complex expression
val arg: Symbolic<InType>
fun createOp(mesh: Symbolic<InType>) : OpType
override val variables
get() = arg.variables
override fun <V : Any> substituteInside(find: Symbolic<V>, replace: Symbolic<V>): OpType {
return createOp(arg.substitute(find, replace))
}
}
The interface can then be implemented as follows: these classes represent the operation of getting some component of an expression.
data class GetX(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetX> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetX(arg)
override fun eval() = arg.eval().x
}
data class GetY(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetY> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetY(arg)
override fun eval() = arg.eval().y
}
data class GetZ(override val arg: Symbolic<Vector3d>) : UnarySymbolicOp<Vector3d, Double, GetZ> {
override fun createOp(mesh: Symbolic<Vector3d>) = GetZ(arg)
override fun eval() = arg.eval().z
}
This improves things as other methods returning a copy of the object can use that method and thus can live in the interface, but I still have to copy this method everywhere, while it basically always does the same thing.