Skip to content

Commit

Permalink
Fix MQTT with Jackson (#355)
Browse files Browse the repository at this point in the history
* Fix MQTT with Jackson

mqtt-core was based on serde-jackson which may be missing if the consuming project is using jackson.

This change mirrors the fix for problem-json here micronaut-projects/micronaut-problem-json#293

That is, make the serde-api and jackson annotations api dependencies of this project in place of the serde-jackson dependency.

I have an external reproducer, but I cannot get it to fail when included in this project...

Closes #332

* Add tests
  • Loading branch information
timyates committed Jan 9, 2024
1 parent cb0940a commit 2c651c4
Show file tree
Hide file tree
Showing 14 changed files with 185 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ dependencies {
testImplementation(mn.micronaut.management)
testImplementation(mn.reactor)
testImplementation(projects.testSuiteUtils)
testImplementation(mnSerde.micronaut.serde.jackson)
}
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[versions]
micronaut-docs = "2.0.0"
micronaut = "4.1.11"
micronaut-platform = "4.1.6"
micronaut-gradle-plugin = "4.1.2"
groovy = "4.0.15"
spock = "2.3-groovy-4.0"
Expand All @@ -23,6 +24,7 @@ micronaut-logging = "1.1.2"
[libraries]
# Core
micronaut-core = { module = 'io.micronaut:micronaut-core-bom', version.ref = 'micronaut' }
micronaut-platform = { module = 'io.micronaut.platform:micronaut-platform', version.ref = 'micronaut-platform' }
micronaut-reactor = { module = "io.micronaut.reactor:micronaut-reactor-bom", version.ref = "micronaut-reactor" }
micronaut-serde = { module = "io.micronaut.serde:micronaut-serde-bom", version.ref = "micronaut-serde" }
micronaut-validation = { module = "io.micronaut.validation:micronaut-validation-bom", version.ref = "micronaut-validation" }
Expand Down
3 changes: 2 additions & 1 deletion mqtt-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ dependencies {
api(mn.micronaut.inject)
api(mn.micronaut.aop)
api(mn.micronaut.messaging)
api(mnSerde.micronaut.serde.api)
api(mn.jackson.annotations)
implementation(mn.micronaut.retry)
implementation(mnSerde.micronaut.serde.jackson)
implementation(mn.reactor)
compileOnly(libs.kotlin.stdlib.jdk8)
}
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ include 'mqtt-bom'

include 'test-suite-groovy'
include 'test-suite'
include 'test-suite-jackson'
include 'test-suite-kotlin'
include 'test-suite-mqttv3-graal'
include 'test-suite-mqttv5-graal'
Expand Down
1 change: 1 addition & 0 deletions test-suite-groovy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ dependencies {
testCompileOnly(mnValidation.micronaut.validation)
testImplementation projects.testSuiteUtils
testImplementation projects.micronautMqttv5
testImplementation(mnSerde.micronaut.serde.jackson)
}

tasks.named('test') {
Expand Down
29 changes: 29 additions & 0 deletions test-suite-jackson/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id("io.micronaut.library")
id("io.micronaut.test-resources")
}

version = "0.1"
group = "example.micronaut"

repositories {
mavenCentral()
}

dependencies {
implementation(projects.micronautMqttv5)
implementation(mn.micronaut.jackson.databind)
runtimeOnly(mn.snakeyaml)
runtimeOnly(mnLogging.logback.classic)

testImplementation(libs.awaitility)
}

micronaut {
version.set(libs.versions.micronaut.platform)
testRuntime("junit5")
processing {
incremental(true)
annotations("example.micronaut.*")
}
}
32 changes: 32 additions & 0 deletions test-suite-jackson/src/main/java/example/micronaut/Odour.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.micronaut;

import io.micronaut.core.annotation.Introspected;

@Introspected
public class Odour {

private final String name;

public Odour(String name) {
this.name = name;
}

public String getName() {
return name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2017-2024 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package example.micronaut;

import io.micronaut.core.annotation.NonNull;
import io.micronaut.mqtt.annotation.MqttSubscriber;
import io.micronaut.mqtt.annotation.Topic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@MqttSubscriber
public class SmellListener {

private static final Logger LOG = LoggerFactory.getLogger(SmellListener.class);
private Odour smell;

@Topic("house/livingroom/smell")
public void receive(Odour data) {
LOG.info("smell: {}", smell);
smell = data;
}

@NonNull
public String getSmell() {
return smell == null ? "" : smell.getName();
}
}
18 changes: 18 additions & 0 deletions test-suite-jackson/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#tag::mqtt[]
mqtt:
client:
server-uri: tcp://${mqtt.host}:${mqtt.port}
client-id: ${random.uuid}
#end::mqtt[]
#tag::test-resources[]
test-resources:
containers:
mosquitto:
image-name: eclipse-mosquitto
hostnames:
- mqtt.host
exposed-ports:
- mqtt.port: 1883
ro-fs-bind:
- "src/test-resources/mosquitto.conf": /mosquitto/config/mosquitto.conf
#end::test-resources[]
14 changes: 14 additions & 0 deletions test-suite-jackson/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<configuration>

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>

<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
5 changes: 5 additions & 0 deletions test-suite-jackson/src/test-resources/mosquitto.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
persistence false
allow_anonymous true
connection_messages true
log_type all
listener 1883
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package example.micronaut;

import io.micronaut.mqtt.annotation.Topic;
import io.micronaut.mqtt.annotation.v5.MqttPublisher;
import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.Test;

import java.util.concurrent.TimeUnit;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;

@MicronautTest
class SubscriptionTest {

@Inject
SmellClient client;

@Inject
SmellListener listener;

@Test
void checkSubscriptionsAreReceived() {
client.publishLivingroomSmell(new Odour("cheesy"));

await()
.atMost(5, TimeUnit.SECONDS)
.untilAsserted(() -> assertEquals("cheesy", listener.getSmell()));
}

@MqttPublisher
interface SmellClient {

@Topic("house/livingroom/smell")
void publishLivingroomSmell(Odour data);
}
}
1 change: 1 addition & 0 deletions test-suite-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ dependencies {

testImplementation projects.testSuiteUtils
testImplementation projects.micronautMqttv5
testImplementation(mnSerde.micronaut.serde.jackson)
}

tasks.named('test') {
Expand Down
1 change: 1 addition & 0 deletions test-suite/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies {

testImplementation projects.testSuiteUtils
testImplementation projects.micronautMqttv5
testImplementation(mnSerde.micronaut.serde.jackson)
}

tasks.named('test') {
Expand Down

0 comments on commit 2c651c4

Please sign in to comment.