Unmarshalling generic types with Json Spray in Akka Http - akka-http

I have routes in Akka Http(Scala) project which are basically the same (CRUD operations) except for entities they operate on
I have my Json formats defined in JsonSupport trait like this:
trait JsonSupport extends SprayJsonSupport {
import DefaultJsonProtocol._
implicit val userJsonFormat = jsonFormat3(User)
}
Then I have a route defined which extends this trait, so it works fine if I use a concrete type, but as soon as I have a generic type it fails to compile:
def userRoute[T]: Route =
pathPrefix("users") {
post {
entity(as[T]) { user =>
with error:
could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.FromRequestUnmarshaller[T]
I suspect that it can't find implicit value because the type is too broad.
What type constraints should I give the T so it would be able to resolve it?
Is there a way to solve it?
Cheers,
Leonti

Related

kotlinx.serialization JSON replacing default serializers in gradle mpp multiplatform project

I want to use my own custom KSerializer<LocalDateTime> with kotlinx.serialization and kotlinx.datetime
#ExperimentalSerializationApi
#Serializer(forClass = LocalDateTime::class)
object LocalDateTimeSerializer : KSerializer<LocalDateTime> {
...
I create my Json like this:
val JSON = Json {
prettyPrint = true; prettyPrintIndent = " ".repeat(2)
serializersModule = this.serializersModule.apply {
overwriteWith(
SerializersModule {
contextual(Instant::class, InstantSerializer)
contextual(LocalDateTime::class, LocalDateTimeSerializer)
}
)
}
}
but whatever I try, I cannot succeed to replace the default LocalDateTimeIso8601Serializer with mine:
val l = JSON.decodeFromString<LocalDateTime>(s) // does NOT(!) use my own Serializer
// have to give it explicitly to work, but that's not what I want
val l = JSON.decodeFromString<LocalDateTime>(LocalDateTimeSerializer, s) // works, but explicitly
is it possible to replace a default Serializer??
anyone?
This is not possible.
The closest to what you want to achieve is by specifying a default serializer for a full file.
If I'm not mistaken, the reason for this is kotlinx serialization is a reflectionless serializer; all serializers are defined at compile time. Applying #Contextual is a way to disable that behavior and determine a serializer at runtime based on context (not what you are after here). I guess you could request a feature to apply a default serializer to a full module (likely already requested), but I can see how it's harder to implement/can lead to more unexpected conflicts/behavior than on file scope, which is why it may currently not be supported.
As a hack, you could consider using a wrapper type for LocalDateTime which uses your custom serializer. But, I'd recommend against this. Essentially, this is the same as applying the annotation everywhere, in that at every occurrence you need to make sure to use the right type.

Kotlin Flow out generic

I am using flow{} builder to call the api and then emit() the response to ViewModel. I add return type of flow as Flow<Resource<List<RemoteData>>>. However, at some places in emit(), the Android Studio throws
error : Not enough information to infer type variable T
Because the emit(Resource.Error(message = "Couldn't reach server, check your internet connection.")) is expecting values of type List<RemoteData> Please see my Resource class below
sealed class Resource<T>(val data: T? = null, val message: String? = null) {
class Loading<T>(data: T? = null): Resource<T>(data)
class Success<T>(data: T?): Resource<T>(data)
class Error<T>(message: String, data: T? = null): Resource<T>(data, message)
}
My question, Is it safe to change emit to
emit(Resource.Error(
message = "Couldn't reach server, check your internet connection.",
data = null
))
And flow's return type as Flow<Resource<out List<RemoteData>>> ?
Kotlin has declaration site variance. I would put out at the Resource class declaration. Then when you declare your type Flow<Resource<List<RemoteData>>>, it will already be implicitly out List<RemoteData>.
Also, your Resource classes look convoluted to me. If data is the loaded resource, it should not be part of the Loading or Error classes. Why force every instance of Loading and Error to carry a meaningless null data value? Likewise, the message should not be part of the Loading and Success cases.
I would rewrite your sealed class as a sealed interface (since it has no shared state between types) like this, and take advantage of data class features as well. Loading can be an object because it doesn't need to hold state. Loading and Error can both be Resource<Nothing> since the type T is irrelevant to any specific instance of them. That way you won't have to needlessly specify types when using them, like having to put <RemoteData> after is Resource or is Error in a when statement.
sealed interface Resource<out T> {
object Loading: Resource<Nothing>
data class Success<out T>(val data: T): Resource<T>
data class Error(val message: String): Resource<Nothing>
}
This version of the sealed classes will be much easier to use. The compiler will be more lenient with how and where you need to specify generic types.

Quarkus/Kotlin: An annotation argument must be a compile-time constant with a java class

In a quarkus/kotlin app, I have a rest client that is very basic:
#Path("/my/api/v1")
#RestClient
interface MyApiClient { }
Problem is, when a request fails, it returns a response that fails to be mapped. So I want to add an exception mapper, in order to log the real error:
class MyExceptionMapper : ResponseExceptionMapper<java.lang.RuntimeException?> {
override fun toThrowable(r: Response): java.lang.RuntimeException {
Logger.getLogger(MyApiClient::class.java).error(r.status)
return RuntimeException("failed")
}
}
To do so, I should annoate my client with:
#RegisterProvider(MyExceptionMapper::class.java)
Doing so, I have a kotlin error:
An annotation argument must be a compile-time constant
I googled but could find solutions only for strings. In this case, kotlin expects the java class to be a compile time constant. How to get it?
Should work with simple:
#RegisterProvider(MyExceptionMapper::class)

How to resolve a service by implementation type?

Let's say I have the following setup:
interface IDoSomething { }
class Something : IDoSomething { }
class AnotherThing : IDoSomething { }
I register the classes with the built-in DI container like this:
services.AddTransient<IDoSomething, Something>();
services.AddTransient<IDoSomething, AnotherThing>();
I have no problem resolving both of these by injecting IEnumerable<IDoSomething>. But, I need a way to resolve a specific one by the implementation type. Something like:
var x = serviceProvider.GetService<Something>();
(where serviceProvider is IServiceProvider)
However, this always returns null.
If I add the following registration, this works fine:
services.AddTransient<Something>();
Is there a way to resolve a dependency by the implementation type without having to register the type twice (once so I can resolve by the interface and the other so I can resolve by the implementation type)?

Validation Data Class Parameters Kotlin

If I am modeling my value objects using Kotlin data classes what is the best way to handle validation. Seems like the init block is the only logical place since it executes after the primary constructor.
data class EmailAddress(val address: String) {
init {
if (address.isEmpty() || !address.matches(Regex("^[a-zA-Z0-9]+#[a-zA-Z0-9]+(.[a-zA-Z]{2,})$"))) {
throw IllegalArgumentException("${address} is not a valid email address")
}
}
}
Using JSR-303 Example
The downside to this is it requires load time weaving
#Configurable
data class EmailAddress(#Email val address: String) {
#Autowired
lateinit var validator: Validator
init {
validator.validate(this)
}
}
It seems unreasonable to me to have object creation validation anywhere else but in the class constructor. This is the place responsible for the creation, so that is the place where the rules which define what is and isn't a valid instance should be. From a maintenance perspective it also makes sense to me as it would be the place where I would look for such rules if I had to guess.
I did make a comment, but I thought I would share my approach to validation instead.
First, I think it is a mistake to perform validation on instantiation. This will make the boundary between deserialization and handing over to your controllers messy. Also, to me, if you are sticking to a clean architecture, validation is part of your core logic, and you should ensure with tests on your core logic that it is happening.
So, to let me tackle this how I wish, I first define my own core validation api. Pure kotlin. No frameworks or libraries. Keep it clean.
interface Validatable {
/**
* #throws [ValidationErrorException]
*/
fun validate()
}
class ValidationErrorException(
val errors: List<ValidationError>
) : Exception() {
/***
* Convenience method for getting a data object from the Exception.
*/
fun toValidationErrors() = ValidationErrors(errors)
}
/**
* Data object to represent the data of an Exception. Convenient for serialization.
*/
data class ValidationErrors(
val errors : List<ValidationError>
)
data class ValidationError(
val path: String,
val message: String
)
Then I have a framework specific implementations. For example a javax.validation.Validation implementation:
open class ValidatableJavax : Validatable {
companion object {
val validator = Validation.buildDefaultValidatorFactory().validator!!
}
override fun validate() {
val violations = validator.validate(this)
val errors = violations.map {
ValidationError(it.propertyPath.toString(), it.message)
}.toMutableList()
if (errors.isNotEmpty()) {
throw ValidationErrorException(errors = errors)
}
}
}
The only problem with this, is that the javax annotations don't play so well with kotlin data objects - but here is an example of a class with validation:
import javax.validation.constraints.Positive
class MyObject(
myNumber: BigDecimal
) : ValidatableJavax() {
#get:Positive(message = "Must be positive")
val myNumber: BigDecimal = myNumber
}
Actually, it looks like that validation is not a responsibility of data classes. data tells for itself — it's used for data storage.
So if you would like to validate data class, it will make perfect sense to set #get: validation on arguments of the constructor and validate outside of data class in class, responsible for construction.
Your second option is not to use data class, just use simple class and implement whole logic in the constructor passing validator there
Also, if you use Spring Framework — you can make this class Bean with prototype scope, but chances are it will be absolutely uncomfortable to work with such kind of spaghetti-code :)
I disagree with your following statement :
Seems like the init block is the only logical place since it executes after the primary constructor.
Validation should not be done at construction time, because sometimes, you need to have intermediate steps before getting a valid object, and it does not work well with Spring MVC for example.
Maybe use a specific interface (like suggested in previous answer) with a method dedicated to executing validation.
For the validation framework, I personnaly use valiktor, as I found it a lot less cumbersome that JSR-303