Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GraalVM native-image #14

Merged
merged 6 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ class TestService(private val mqttClient: Mqtt3Client) {
}
```

### GraalVM

This starter supports GraalVM out of the box. There is nothing special to do.

### Upgrade Guide

#### 0.15.0 -> 0.16.0
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_17
allWarningsAsErrors = true
javaParameters = true
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.hivemq.client.mqtt.mqtt5.Mqtt5Client
import io.reactivex.Scheduler
import io.reactivex.schedulers.Schedulers
import org.slf4j.LoggerFactory
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding
import org.springframework.boot.autoconfigure.AutoConfiguration
import org.springframework.boot.autoconfigure.AutoConfigureAfter
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass
Expand All @@ -30,6 +31,7 @@ import java.util.concurrent.Executor
@Import(MqttSubscriberCollector::class)
@ConditionalOnClass(MqttClient::class)
@ConditionalOnProperty("mqtt.enabled", matchIfMissing = true)
@RegisterReflectionForBinding(MqttProperties::class)
@EnableConfigurationProperties(MqttProperties::class)
class MqttAutoConfiguration {

Expand Down Expand Up @@ -126,6 +128,7 @@ class MqttAutoConfiguration {
fun immediateMqttScheduler(): Scheduler = Schedulers.computation()

@Bean
@ConditionalOnMissingBean
fun mqttMessageAdapter(objectMapper: ObjectMapper): MqttMessageAdapter = DefaultMqttMessageAdapter(objectMapper)

/**
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/de/smartsquare/starter/mqtt/MqttProperties.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ data class MqttProperties(
/**
* The port the mqtt broker is available under.
*/
@field:Min(1)
@field:Max(65535)
@get:Min(1)
@get:Max(65535)
val port: Int = 0,

/**
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/de/smartsquare/starter/mqtt/MqttSubscribe.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package de.smartsquare.starter.mqtt

import com.hivemq.client.mqtt.datatypes.MqttQos
import org.springframework.aot.hint.annotation.Reflective

/**
* Marker annotation for methods that should receive messages from the mqtt broker.
*/
@Reflective
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
annotation class MqttSubscribe(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ package de.smartsquare.starter.mqtt
import com.hivemq.client.mqtt.datatypes.MqttQos
import com.hivemq.client.mqtt.datatypes.MqttTopicFilter
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.ObjectProvider
import org.springframework.beans.factory.config.BeanPostProcessor
import org.springframework.context.annotation.Lazy
import org.springframework.core.annotation.AnnotationUtils
import java.lang.reflect.Method

/**
* Helper class to find all beans with methods annotated with [MqttSubscribe].
*/
class MqttSubscriberCollector(@Lazy private val config: MqttProperties) : BeanPostProcessor {
class MqttSubscriberCollector(configProvider: ObjectProvider<MqttProperties>) : BeanPostProcessor {

private val logger = LoggerFactory.getLogger(javaClass)

/**
* It's really important to use lazy initialization here, because the bean value inside this provider is not
* available during construction time and only requested lazy up on the first found subscriber.
* At this point, the bean is already available and can be used.
* We cache the result here to avoid multiple expensive lookups from the underlying bean factory.
*/
private val config: MqttProperties by lazy { configProvider.`object` }

/**
* MultiMap of beans to its methods annotated with [MqttSubscribe] and the annotation itself.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test

object TestMqttSubscriberCollector {
operator fun invoke(bean: Any): MqttSubscriberCollector = MqttSubscriberCollector(MqttProperties()).apply {
operator fun invoke(bean: Any) = MqttSubscriberCollector(TestObjectProvider(MqttProperties())).apply {
postProcessAfterInitialization(bean, "testBean")
}
}
Expand All @@ -21,7 +21,7 @@ class MqttHandlerTest {
private val messageErrorHandler = MqttMessageErrorHandler()

@Test
fun `invoke correct method for multiple subsciber methods`() {
fun `invoke correct method for multiple subscriber methods`() {
val subscriber = object {
var invoked = false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class MqttSubscriberCollectorIntegrationTests {
class PostProcessorConfiguration {

@Bean
fun annotationCollector() = MqttSubscriberCollector(MqttProperties())
fun annotationCollector() = MqttSubscriberCollector(TestObjectProvider(MqttProperties()))

@Bean
fun subscriber() = Subscriber()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.junit.jupiter.api.Test

class MqttSubscriberCollectorTests {

private val annotationCollector = MqttSubscriberCollector(MqttProperties(group = "group"))
private val annotationCollector = MqttSubscriberCollector(TestObjectProvider(MqttProperties(group = "group")))

@Test
fun `processes bean`() {
Expand Down
10 changes: 10 additions & 0 deletions src/test/kotlin/de/smartsquare/starter/mqtt/TestObjectProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package de.smartsquare.starter.mqtt

import org.springframework.beans.factory.ObjectProvider

class TestObjectProvider<T : Any>(private val data: T) : ObjectProvider<T> {
override fun getObject(vararg args: Any?): T = data
override fun getObject(): T = data
override fun getIfAvailable(): T = data
override fun getIfUnique(): T = getObject()
}