How can i limit use of enum values in Kotlin? - kotlin

Can I somehow limit the usage of incoming enum with kotlin language features?
I have an enum, for example
enum class Message {
NORMAL,
URGENT,
LETHAL
}
When i get an incoming dto, i need to assure that it contains only URGENT or LETHAL enum values. I'm a bit lazy to write a validator, so could anyone advice some kotlin magick for that case?

Simple require assertion:
val message = Message.NORMAL
require(message in listOf(URGENT, LETHAL)) { "Message must be either urgent or lethal" }

Related

Map of generic interfaces in Kotlin

I stuck with some simple thing) Let's say I have following:
interface IMessagePayload // marker interface
data class IdPayload(
val id: Long
) : IMessagePayload
data class StringPayload(
val id: String,
) : IMessagePayload
Then I have a class:
data class Message<T : IMessagePayload>(
val id: String,
val payload: T,
)
Also I have some interface describing processor of this message:
interface IMessageProcessor<T : IMessagePayload> {
fun process(message: Message<T>)
}
And some implementation:
class ProcessorImpl : IMessageProcessor<IdPayload> {
override fun process(message: Message<IdPayload>) {
}
}
Now I wanna have a map of such processors. Lets use some enum type as a keys of this map:
enum class ActionType {
UPDATE,
DELETE,
ADD
}
private var map = mutableMapOf<ActionType, IMessageProcessor<IMessagePayload>>()
map[ActionType.ADD] = ProcessorImpl() // <-- error here
And that's where the problem occurs. I cannot put my ProcessorImpl into this map. The compiler says that there is an error: Type mismatch. Required: IMessageProcessor. Found: ProcessorImpl().
I could declare the map in the following way (using star projection):
private var map = mutableMapOf<ActionType, IMessageProcessor<*>>()
But in this case I cannot call processors's process method fetching it from the map by key first:
map[ActionType.ADD]?.process(Message("message-id", IdPayload(1))) // <-- error here
Compiler complains: Type mismatch. Required nothing. Found Message<IdPayload>
What am I doing wrong? Any help is appreciated.
This is about variance.
IMessageProcessor is defined as interface IMessageProcessor<T : IMessagePayload>; it has one type parameter, which must be IMessagePayload or a subtype.
But it is invariant in that type parameter; an IMessageProcessor< IdPayload> is not related to an IMessageProcessor<IMessagePayload>.  In particular, it's not a subtype.
And your map is defined with a value type IMessageProcessor<IMessagePayload>.  So its value cannot be an IMessageProcessor< IdPayload>, because that's neither the value type, nor a subtype.  Hence the compile error.
In this case, the simplest way to get it to compile is to change your map:
private var map = mutableMapOf<ActionType, IMessageProcessor<out IMessagePayload>>()
The only difference there is the out; that tells the compiler that the value IMessageProcessor is covariant in its type parameter.  (It may help to think of out as meaning ‘…or any subtype’.  Similarly, you could make it contravariant by using in, which you might think of as ‘…or any supertype’.)
This lets you store in the map an IMessageProcessor for any subtype of IMessagePayload.
However, if you do that, you'll find that you can't use any value you pull out of your map — because it can't tell which messages the processor can handle, i.e. which subtype of IMessagePayload it works for!  (The compiler expresses this as expecting a type parameter of Nothing.)
In general, it's often better to specify variance on the interface or superclass itself (declaration-site variance) rather than the use-site variance shown above.  But I can't see a good way to do that here, because you have multiple generic classes, and they interact in a complicated way…)
Think for a moment what IMessageProcessor's type parameter means: it's the type of message that the processor can consume. So an IMessageProcessor<A> can handle messages of type Message<A>.
Now, a subtype must be able to do everything its supertype can do (and usually more) — otherwise you can't drop that subtype anywhere that's expecting to use the supertype.  (That has the grand name of the Liskov substitution principle — but it's really just common sense.)
So an IMessageProcessor<B> is a subtype of IMessageProcessor<A> only if it can handle at least all the messages that an IMessageProcessor<A> can.  This means it must accept all messages of type Message<A>.
But Message is invariant in its type parameter: a Message<B> is not directly related to a Message<A>.  So you can't write a processor that handles them both.
The most natural solution I can find is to specify variance on both Message and IMessageProcessor:
data class Message<out T : IMessagePayload>( /*…*/ )
interface IMessageProcessor<in T : IMessagePayload> { /*…*/ }
And then use a wildcard in your map to make it explicit that you don't know anything about the type parameters of its values:
private var map = mutableMapOf<ActionType, IMessageProcessor<*>>()
That lets you safely store a ProcessorImpl() in the map.
But you still have to use an (unchecked) cast on the values you pull out of the map before you can use them:
(map[ActionType.ADD] as IMessageProcessor<IdPayload>)
.process(Message("4", IdPayload(4L)))
I don't think there's any easy way around that, because the problem is inherent in having values which are processors that can handle only some (unknown) types of message.
I'm afraid the best thing would be to have a rethink about what these classes mean and how they should interact, and redesign accordingly.

ULong Jackson (de)serializer

I have an endpoint that receives an DTO into the body.
The DTO has a ULong attribute that the Jackson do not parse (deserialize) when I request the
endpoint with postman.
Also, I try to create my custom serializer?
class ULongSerializer: StdSerializer<ULong>{
override fun serializer(value: ULong, gen: JsonGenarator, provader: SerializerProvider){
gen.writeStartObject()
gen.writeNumber(value) //HERE IS THE PROBLEM
gen.writeEndObject
}
}
neither write number method do not support ULong, nor another methods like write field.
Can someone give me some tips to deal with this?
ULong is a class and you may write Jackson serializer/deserializer for it, but a field of this type is compiled to bytecode as a field of primivite long type. So values exceeding Long.MAX_VALUE would be serialized/deserialized incorrectly (as negative), and custom serializer/deserializer won't help you.
Take a look at kotlinx.serialization. It have OOTB experimental support for unsigned integer types. See https://github.com/Kotlin/kotlinx.serialization/blob/master/CHANGELOG.md#experimental-support-for-inline-classes-ir-only

Axon no Handler Found for query when returning Response with Generic

We are having issues when our Axon QueryHandler is returning a Class with a Generic parameter like QueryResult<T>.
For example:
class QueryResult<T>(val values: List<T>, val status: Status,
var text: String? = null) : Serializable {
...
}
And our query handler:
#QueryHandler
fun handle(query: SomeQuery): QueryResult<String>{
Axon is giving us the following message:
NoHandlerForQueryException: No handler found for [SomeQuery] with
response type [InstanceResponseType{class QueryResult}]
Is using Generics allowed in QueryHandlers or do we have to call queryGateway in some specific way?
Axon will only resolve generics for the following return types:
Collections
Futures
Optionals
I believe your desired query response would require a new implementation of the ResponeType interface, which will do even further inspection upon the available generics.
Short answer? What you're trying to do isn't possible at the moment.
The documentation is relative short on this, but still clear I think. If you disagree on that, you're free to provide a pull request or open up an issue to request for clarity on the matter.

Using kotlin expression annotations

Kotlin allows to annotate expressions. It is however unclear, how such annotations may be useful and how to use them.
Let's say in following example I would like to check, that string contains number specified in #MyExpr annotation. Can this be achieved and how?
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class MyExpr(val i: Int) {}
fun someFn() {
val a = #MyExpr(1) "value#1";
val b = #MyExpr(2) "value#2";
}
Specifying #Target(AnnotationTarget.EXPRESSION) is just a way of telling the compiler where the user of the annotation can put it.
It does not do anything on it's own rather than that.
So e.g.
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class Something
// compiler will fail here:
#Something class Foo {
// but will succeed here:
val a = #Something "value#1"
}
Unless you're writing an Annotation Processor (so a thing that looks for Annotations and does something with them), your annotations have just informational value. They are just a signal to other devs (or future You) of something.
#Target(AnnotationTarget.EXPRESSION)
#Retention(AnnotationRetention.SOURCE)
annotation class UglyAndOldCode
val a = #UglyAndOldCode "this is something old and requires refactoring"
If you want to implement what you've stated in your question you would have to create an Annotation Processor that checks expressions marked with MyExpr for the condition that you've specified.

Kotlin - "in" keyword - what is is used for?

i am trying to understand when to use the "in" keyword in generics as opposed to the "out" keyword (which allows assigning to subclasses).
I am actually following this tutorial if it matters.
Lets say we have the following class defintiion:
class ParameterizedConsumer<in T> {
fun toString(value: T): String {
return value.toString()
}
}
How does this even compile since value is not guaranteed to be a String ? is this what the in keyword does ? it tells the class that there is a guarantee the type wont be any other subclass ? I am just not clear on the usecase for it, can you help ?
the tutorial says i will be able to call the following but i am lost as to what it has changed:
val parameterizedConsumer = ParameterizedConsumer<Number>()
val ref: ParameterizedConsumer<Double> = parameterizedConsumer
assertTrue(ref is ParameterizedConsumer<Double>)
UPDATE: I get it now. Out means you can downcast when producing. and "In" means you can downcast when assigning.
So in java this is not allowed:
// Java
void demo(Source<String> strs) {
Source<Object> objects = strs; // !!! Not allowed in Java
// ...
}
but in kotlin we can fix that if we use the "out" keyword we can assign to a downcasted class (subclass). likewise with "in" we can pass in a subclass into the class internally to use but not outwardly.
it tells the class that there is a guarantee the type wont be any other subclass ? I am just not clear on the usecase for it, can you help ?
Say you have a function that wants to add some items to a list you supply. The items are of type Int.
Question: what kinds of list are acceptable to this function?
Answer: MutableList<Int>, MutableList<Number>, MutableList<Any>. Or, in short, MutableList<in Int>.
In the same spirit, let's explain the out projection.
Say you have a function that wants to get some elements from a list you supply. The items are of type Future.
Question: what kinds of list are acceptable to this function?
Answer: List<Future>, List<RunnableFuture>, List<ScheduledFuture>... or, in short, List<out Future>.
I'll answer part of your question
How does this even compile since value is not guaranteed to be a String
So what? You can call .toString() on any type. That's how you get a string you'll be returning.