How to inject HTTP client from library in Micronaut app? - kotlin

I have an external http client to other service and I've imported it to my micronaut app but receives an error which points:
Caused by: io.micronaut.context.exceptions.NoSuchBeanException: No bean of type [xxx.files.client.micronaut.FilesClient] exists. Make sure the bean is not disabled by bean requirements (enable trace logging for 'io.micronaut.context.condition' to check) and if the bean is enabled then ensure the class is declared a bean and annotation processing is enabled (for Java and Kotlin the 'micronaut-inject-java' dependency should be configured as an annotation processor).
I've added these classes when the app starts:
object TransformerApplication {
#JvmStatic
fun main(args: Array<String>) {
Micronaut.build()
.packages(
"xxx.transformer",
"xxx.files.client.micronaut"
)
.mainClass(TransformerApplication.javaClass)
.start()
}
}
But when creating:
#KafkaListener("transformer-group")
class EventsConsumerImpl(private val xlsTransformer: XlsTransformer,
private val filesClient: FilesClient,
private val workspacesClient: WorkspacesClient) : EventsConsumer {
...
}
My http-client:
#io.micronaut.http.client.annotation.Client("\${files.url}")
interface FilesClient {
companion object {
const val FILES_TOKEN_KEY = "FILES"
}
#FilesTokenVerification
#Get("\${files.url}/{fileId}")
fun getFile(#PathVariable fileId: String): ByteArray
#FilesTokenVerification
#Patch("\${files.url}/{fileId}/info")
fun updateFileStatus(#PathVariable fileId: String, #Body metadata: Metadata): Metadata
#FilesTokenVerification
#Get("\${files.url}/{fileId}/info")
fun getFileMetadata(#PathVariable fileId: String): Metadata
}```
Can someone explain to me what I'm doing wrong?

is usuallay use a factory for that:
https://docs.micronaut.io/latest/guide/index.html#factories
but i do not know if that works with declarative clients.
Maybe try a wrapper around.

Related

Error when consuming event with Vert.x: Unable to find an EntityManagerFactory

i'm using Quarkus, Vert.x and Kotlin and trying to call my code through a unit test while using #QuarkusTest and #TestTransaction.
I send out an Event and my Consumer throws an exception when i talk to the database:
2022-05-26 18:38:25,322 ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (vert.x-eventloop-thread-3) Uncaught exception received by Vert.x: java.lang.IllegalArgumentException: Unable to find an EntityManagerFactory for persistence unit '<default>'
at io.quarkus.hibernate.orm.runtime.JPAConfig.getEntityManagerFactory(JPAConfig.java:85)
at io.quarkus.hibernate.orm.runtime.TransactionSessions.lambda$getSession$0(TransactionSessions.java:40)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
...
My consumer looks like this:
#ApplicationScoped
class Consumer {
#Blocking
#ConsumeEvent(EventSet.UPDATE)
#Transactional
fun update(foo: Foo) {
val newFoo = NewFoo.findById(foo.id) ?: let { NewFoo.create(foo.id) }
}
}
I assumed Quarkus whould just make sure that the database works. What am i missing? I looked into hibernate-reactive because it popped up but nothing states that i would need to configure that as well.

Enable Metrics on AWS Lambda Spring Cloud Function using Kotlin

I am working on a POC where I am aiming to create a aws lambda function using spring cloud function, as requirement I also need to be able to generate metrics when the functions run, in spring-cloud-function docs it says this:
Enable Spring Boot features (auto-configuration, dependency injection, metrics) on serverless providers.
However, I am unable to see any metrics in AWS Cloudwatch (not even an empty namespace).
My current setup:
dependencies:
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.cloud:spring-cloud-function-kotlin")
implementation("io.github.microutils:kotlin-logging:${Versions.kotlinLogging}")
implementation("org.springframework.cloud:spring-cloud-function-adapter-aws")
implementation("com.amazonaws:aws-lambda-java-runtime-interface-client:${Versions.awsLambdaJavaRuntime}")
implementation("org.springframework.cloud:spring-cloud-function-adapter-aws")
implementation("com.amazonaws:aws-lambda-java-events:${Versions.awsLambdaJavaEvents}")
implementation("com.amazonaws:aws-lambda-java-core:${Versions.awsLambdaJavaCore}")
implementation("net.logstash.logback:logstash-logback-encoder:${Versions.logbackEncoder}")
application.yaml
management:
metrics:
export:
cloudwatch:
enabled: true
step: 1
Config:
#Configuration
#Profile("aws")
class CloudWatchMetrics(
private val config: CloudWatchMetricsConfig
) {
#Bean
fun cloudWatchAsyncClient(): CloudWatchAsyncClient =
CloudWatchAsyncClient.builder().region(Region.EU_WEST_1).build()
#Bean
fun meterRegistry(cloudWatchAsyncClient: CloudWatchAsyncClient): MeterRegistry = CloudWatchMeterRegistry(
cloudWatchConfig(),
Clock.SYSTEM,
cloudWatchAsyncClient
)
private fun cloudWatchConfig(): CloudWatchConfig =
object : CloudWatchConfig {
private val configuration = mapOf(
"cloudwatch.namespace" to config.namespace,
"cloudwatch.step" to Duration.ofMinutes(config.step).toString()
)
override fun get(key: String): String? = configuration[key]
}
Stack Handler Environment Configs (.ts)
environment: {
MAIN_CLASS: springBeanMainClass,
SPRING_PROFILES_ACTIVE: '',
SPRING_DATASOURCE_URL: `jdbc-url`,
SPRING_DATASOURCE_USERNAME: '`user`,...
MANAGEMENT_METRICS_EXPORT_CLOUDWATCH_NAMESPACE: 'MyNamespaceMetric'
},
How do I generate metrics when I run an aws lambda function?

#RestResource(exported = false) not work on findById function of kotlin based spring mvc project

I have the following kotlin repository:
#RepositoryRestResource
interface ChapterRepository: CrudRepository<Chapter, Long> {
#RestResource(exported = false)
override fun findAll(): MutableIterable<Chapter>
#RestResource(exported = false)
override fun findById(id: Long): Optional<Chapter>
}
With the #RestResource annotation above, the findAll is not exposed, but the findById is still exposed. That means I can not access /api/chapters url but /api/chapters/<id> is still accessible.
Below is project info:
Spring Boot version: 2.3.2
Kotlin version: 1.3.72
JDK version: OpenJDK 11.0.6
Thanks for your helps.

REST client interface can not be injected in Quarkus kotlin app

I tried to add a quarkus-rest-client sample for my post-service which is a simple REST API built with Quarkus.
The java version is working well.
When I added another Kotlin to test the kotlin and Gradle support in Quarkus, it failed, the REST Client interface can not be injected as CDI bean.
The PostControlloer is Jaxrs resource to expose an aggregated APIs that combined the original two APIs.
#Path("/api")
#RequestScoped
class PostController(#Inject #RestClient val client: PostResourceClient) {
// #Inject
// #RestClient
// lateinit var client: PostServiceClient
#GET
#Produces(MediaType.APPLICATION_JSON)
fun getPosts(#QueryParam("q")
q: String,
#QueryParam("offset")
#DefaultValue("0")
offset: Int,
#QueryParam("limit")
#DefaultValue("10")
limit: Int): Response {
val posts = this.client.getAllPosts(q, offset, limit).entity as List<Post>
val count = this.client.countAllPosts(q).entity as Long
return ok(PostPage(posts, count)).build()
}
}
The above two approaches to inject a Bean are failed.
The REST Client interface:
#Path("/posts")
#RegisterRestClient
interface PostResourceClient {
#GET
#Produces(MediaType.APPLICATION_JSON)
fun getAllPosts(
#QueryParam("q")
q: String,
#QueryParam("offset")
#DefaultValue("0")
offset: Int,
#QueryParam("limit")
#DefaultValue("10")
limit: Int
): Response
#GET
#Path("count")
#Produces(MediaType.APPLICATION_JSON)
fun countAllPosts(
#QueryParam("q")
q: String
): Response
}
The application config for this Rest Client interface.
com.example.PostResourceClient/mp-rest/url=http://localhost:8080
com.example.PostResourceClient/mp-rest/scope=javax.inject.Singleton
The complete codes is here.
Duplicated with Error to inject some dependency with kotlin + quarkus it is a MicroProfile RestClient issue. See the workaround in the original SO answer:
#Inject
#field: RestClient
lateinit internal var countriesService: CountriesService
An issue is already openned on MicroProfile RestClient to have a fix for this and tracked on the Quarkus issue traker: https://github.com/quarkusio/quarkus/issues/5413

java.lang.UnsupportedOperationException: Packages and file facades are not yet supported in Kotlin reflection

When starting a basic Ktor app, I get:
Exception in thread "main" java.lang.UnsupportedOperationException: Packages and file facades are not yet supported in Kotlin reflection. Meanwhile please use Java reflection to inspect this class: class com.example.ApplicationKt
at kotlin.reflect.jvm.internal.KClassImpl.reportUnresolvedClass(KClassImpl.kt:301)
at kotlin.reflect.jvm.internal.KClassImpl.access$reportUnresolvedClass(KClassImpl.kt:43)
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:53)
at kotlin.reflect.jvm.internal.KClassImpl$Data$descriptor$2.invoke(KClassImpl.kt:44)
at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KClassImpl$Data.getDescriptor(KClassImpl.kt)
at kotlin.reflect.jvm.internal.KClassImpl$Data$objectInstance$2.invoke(KClassImpl.kt:106)
at kotlin.reflect.jvm.internal.ReflectProperties$LazyVal.invoke(ReflectProperties.java:62)
at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
at kotlin.reflect.jvm.internal.KClassImpl$Data.getObjectInstance(KClassImpl.kt)
at kotlin.reflect.jvm.internal.KClassImpl.getObjectInstance(KClassImpl.kt:239)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createModuleContainer(ApplicationEngineEnvironmentReloading.kt:328)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.executeModuleFunction(ApplicationEngineEnvironmentReloading.kt:317)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.instantiateAndConfigureApplication(ApplicationEngineEnvironmentReloading.kt:275)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.createApplication(ApplicationEngineEnvironmentReloading.kt:127)
at io.ktor.server.engine.ApplicationEngineEnvironmentReloading.start(ApplicationEngineEnvironmentReloading.kt:247)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:106)
at io.ktor.server.netty.NettyApplicationEngine.start(NettyApplicationEngine.kt:18)
at io.ktor.server.engine.ApplicationEngine$DefaultImpls.start$default(ApplicationEngine.kt:52)
at io.ktor.server.netty.EngineMain.main(EngineMain.kt:17)
at com.example.ApplicationKt.main(Application.kt:10)
The app is just:
fun main(args: Array<String>): Unit = EngineMain.main(args)
fun Application.demoModule() {
routing {
get("/") {
call.respondText("Hello ${call.parameters["name"]}")
}
}
}
I just noticed the file resources.application.conf had an issue.
It had the wrong module name. I changed com.example.ApplicationKt.module to com.example.ApplicationKt.demoModule:
ktor {
deployment {
port = 8080
port = ${?PORT}
}
application {
modules = [ com.example.ApplicationKt.demoModule ]
}
}
What's annoying is that the error help says nothing about it.