Ktor with Koin DI can't inject, missing clazz - kotlin

I am setting up Koin DI on Ktor in this way:
https://insert-koin.io/docs/reference/koin-ktor/ktor/
But I am getting an error: No value passed for parameter 'clazz'
My implementation looks like this:
import io.ktor.application.*
import io.ktor.routing.*
import org.koin.java.KoinJavaComponent.inject
import services.SomeService
fun Application.registerPropertyRoutes() {
routing {
bodySectionRoute() // add more routes for Property page here
}
}
fun Route.bodySectionRoute() {
val someService by inject<SomeService>()
get("/bodySection") {
// business logic can be connected here
}
}
Any ideas what I am missing?
Update:

You need to import org.koin.ktor.ext.inject

Related

How do I provide my own DateTimeProvider with Spring Data

I am trying to provide a transactionally consistent set of datetimes
import org.springframework.beans.factory.ObjectFactory
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Scope
import org.springframework.data.auditing.DateTimeProvider
import org.springframework.transaction.support.SimpleTransactionScope
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.util.Optional
#Configuration
open class TransactionScopeTimeConfiguration {
#Bean
open fun transactionBFPP(): BeanFactoryPostProcessor =
BeanFactoryPostProcessor { it.registerScope("transaction", SimpleTransactionScope()) }
#Bean
#Scope("transaction")
open fun nowInstant(): Instant = Instant.now()
#Bean
#Scope("transaction")
open fun nowOffsetDateTime(nowInstant: Instant): OffsetDateTime = nowInstant.atOffset(ZoneOffset.UTC)
#Bean
open fun transactionDateTimeProvider(factory: ObjectFactory<OffsetDateTime>): DateTimeProvider =
DateTimeProvider { Optional.of(factory.`object`) }
}
However, when debugging my test I note that the function inside of transactionDateTimeProvider is never called (the creation of the Bean is)
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
#DataJpaTest
#Import(TransactionScopeTimeConfiguration)
internal open class ExceptionDaoTest {
#Test
fun save(#Autowired exceptionDao: ExceptionJpaDao) {
val toCreate = ExceptionEntity("someid")
val saved = exceptionDao.save(toCreate)
assertThat(saved).isInstanceOf(ExceptionEntity::class.java)
.extracting({ it.id }, { it.businessDivisionId })
.containsExactly(toCreate.id, "someid")
.doesNotContainNull()
assertThat(saved.lastModifiedOn).isSameAs(saved.createdOn)
}
}
The test actually passes, but I haven't actually exercised this functionality in this test. It's important that any other datetimes are transactionally consistent with the audit traits.

How to call method Reference in map

I create a class ApUtils . Define two methods in that class . I want
use that two methods in my service class inside the map function by
the help of method reference ,But I am getting un excepted error while
calling these two methods
service.kt
package com.nilmani.reactivespringdemo.services
import com.nilmani.reactivespringdemo.Utils.AppUtils
import com.nilmani.reactivespringdemo.dto.ProductDto
import com.nilmani.reactivespringdemo.entity.Product
import com.nilmani.reactivespringdemo.repository.ProductRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
#Service
class ProductService {
#Autowired
private lateinit var productRepository: ProductRepository
fun getProduct():Flux<ProductDto>{
return productRepository.findAll().map(obj: AppUtils -> obj.entityToDto(product))
}
fun getProduct(id:String):Mono<ProductDto>{
return productRepository.findById(id).map{ obj: AppUtils, product: Product -> obj.entityToDto(product) }
}
}
AppUtils.kt
package com.nilmani.reactivespringdemo.Utils
import com.nilmani.reactivespringdemo.dto.ProductDto
import com.nilmani.reactivespringdemo.entity.Product
import org.springframework.beans.BeanUtils
class AppUtils {
fun entityToDto(product: Product):ProductDto{
val productDto = ProductDto()
BeanUtils.copyProperties(product,productDto)
return productDto
}
fun dtoToEntity(productDto: ProductDto):Product{
val product = Product()
BeanUtils.copyProperties(productDto,product)
return product
}
}
How to call these two function in my service class using method reference
If you change AppUtils to a singleton using Kotlin's object keyword:
object AppUtils { ... }
then you can use method references like so:
fun getProduct(id:String) = productRepository.findById(id).map(AppUtils::entityToDto)

Is there any way to make a fake call from Ktor to itself, to make request pass through all pipeline?

I have an ktor web server that successfully responds on http requests. Now there is a need to read data from kafka's topic and process it.
Is there any way send the data I've read to ktor, like this data came from outside, to make it pass through all pipeline, like ContentNegotiation and other features?
Application class has method execute(), which takes ApplicationCall, but I've found zero examples - how can I fill my implementation of this class properly. Especially route - do I need the real one? Would be nice if this route would be private and would be unavailable from the outside.
You can use the withTestApplication function to test your application's modules without making an actual network connection. Here is an example:
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.request.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.testing.*
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
class SimpleTest {
#Test
fun test() = withTestApplication {
application.module()
// more modules to test here
handleRequest(HttpMethod.Post, "/post") {
setBody("kafka data")
}.response.let { response ->
assertEquals("I get kafka data", response.content)
}
}
}
fun Application.module() {
routing {
post("/post") {
call.respondText { "I get ${call.receiveText()}" }
}
}
}
I think that #AlekseiTirman answer is great and most probably you should go for it
But I have to mention that it's easy to do it even in "real life" run. Your local machine ip is 0.0.0.0, you can get port from the env variable, so you just can create a simple HttpClient and send a request:
CoroutineScope(Dispatchers.IO).launch {
delay(1000)
val client = HttpClient {
defaultRequest {
// actually this is already a default value so no need to setting it
host = "0.0.0.0"
port = environment.config.property("ktor.deployment.port").getString().toInt()
}
}
val result = client.get<String>("good")
println("local response $result")
}
routing {
get("good") {
call.respond("hello world")
}
}

Get request to Ktor Location results in an Unhandled request

I just want to use the Locations Feature of Ktor for my API and I tested it with two simple get requests. The problem is that Ktor seems to ignore my #Locations and if I use the Logging feature it says that the request is unhandled:
TRACE Application - Unhandled: GET - /register
My Application class:
import io.ktor.application.*
import io.ktor.features.*
import io.ktor.gson.*
import io.ktor.locations.*
import io.ktor.response.*
import io.ktor.routing.*
fun Application.main() {
install(Locations)
install(CallLogging)
install(ContentNegotiation) {
gson {
setPrettyPrinting()
}
}
routing {
get("/health_check") {
call.respondText("OK")
}
auth()
}
}
Auth class:
import io.ktor.application.*
import io.ktor.locations.*
import io.ktor.response.*
import io.ktor.routing.*
#Location("/register")
data class Register(val username: String, val email: String, val password: String)
#Location("/login")
data class Login(val username: String, val password: String)
fun Route.auth() {
get<Register> {
call.respondText("Register")
}
get<Login> {
call.respondText("Login")
}
}
I tried to find some information about my problem, but I haven't found any. I thought it might have something to do with the fact that the Locations API of Ktor is still experimental. I hope this is enough information. Thanks in advance.

How can I configure a JAX-RS application in Kotlin with resources having other dependencies injected

I use JAX-RS to build a REST API. To bootstrap all resources I have a overridden an "Application":
import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationScoped
#ApplicationPath("/")
open class ApiConfig : Application() {
override fun getSingletons(): MutableSet<Any> {
println("----- init jaxrs -----")
return mutableSetOf(EchoResource())
}
}
As you can see I register the EchoResource() with brackets. It does not work when I use EchoResource::class.
My Problem is, that I want to inject some service into EchoResource:
import dev.elysion.mail.smtp.MailService
import javax.enterprise.context.RequestScoped
import javax.inject.Inject
import javax.ws.rs.GET
import javax.ws.rs.Path
#Path("/echo")
#RequestScoped
class EchoResource #Inject constructor(private val mailService: MailService) {
#GET
fun getHello(): String {
return "Hello World"
}
}
When I add the constructor I get an error in API Config saying that I do not pass a parameter for MailService.
In Java I would register the resource with EchoResource.class which does not care about any parameters.
How can I achieve the same with Kotlin?
It works if getClasses() is used instead of getSingletons():
import javax.enterprise.context.ApplicationScoped
import javax.ws.rs.ApplicationPath
import javax.ws.rs.core.Application
#ApplicationScoped
#ApplicationPath("/")
open class ApiConfig : Application() {
override fun getClasses(): MutableSet<Class<*>> {
return mutableSetOf(EchoResource::class.java)
}
}
Furthermore, all resources and all of their methods need to be open (not final) in order to be proxyable for CDI.