Skip to content

Add Inbound Channel Adapter for MQTT based on hivemq - #10989

Open
mjd507 wants to merge 10 commits into
spring-projects:mainfrom
mjd507:hivemq-mqtt
Open

mjd507 wants to merge 10 commits into
spring-projects:mainfrom
mjd507:hivemq-mqtt

Conversation

@mjd507

@mjd507 mjd507 commented May 6, 2026

Copy link
Copy Markdown
Contributor

Related to: #3102

To avoid constructor explosion, only MqttClientBuilder or MqttClientManager are designed as input params for building the adapters.

The MqttClientManager requires a MqttClientBuilder as well.

When build the underlying MqttClient, the config from the input MqttClientBuilder will be cloned to avoid global side effect.

@mjd507
mjd507 force-pushed the hivemq-mqtt branch 2 times, most recently from 8ed760f to 6d981ef Compare May 8, 2026 01:09
@mjd507

mjd507 commented May 12, 2026

Copy link
Copy Markdown
Contributor Author

here is the PR in my own repo for outbound v3/v5 adapters (mjd507#1).
I will modify and raise it once the inbound review completed.

Comment thread build.gradle Outdated
@mjd507
mjd507 marked this pull request as draft August 7, 2026 01:13
@artembilan
artembilan requested a review from cppwfs August 12, 2026 15:14
@artembilan

Copy link
Copy Markdown
Member

@cppwfs ,

this is no rush: for the next milestone or so.
Not for just planned release next week.

Thanks

@mjd507
mjd507 marked this pull request as ready for review August 15, 2026 22:39
Related to: spring-projects#3102

To avoid constructor explosion, only `MqttClientBuilder` or `MqttClientManager` are designed as input params for building the adapters.

The `MqttClientManager` requires a `MqttClientBuilder` as well.

When build the underlying `MqttClient`,
the config from the input `MqttClientBuilder` will be cloned to avoid global side effect.

Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
mjd507 added 4 commits August 18, 2026 16:37
Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>

@cppwfs cppwfs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for this great contribution! We look forward to your updates for the requested changes!

Comment thread gradle/libs.versions.toml Outdated
…into hivemq-mqtt

Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>

# Conflicts:
#	gradle/libs.versions.toml
… the mqttClient.

- catch a RuntimeException around `sendMessage`, in case failure happens on Netty I/O thread.
- change root package from `org` to `com`
- use `Mosquitto` for faster startup time.
- add `this` prefix for member fields usage
- docs and tests improvement

Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
- remove try-catch around `sendMessage`

Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
@mjd507
mjd507 requested review from artembilan and cppwfs September 15, 2026 05:06

@cppwfs cppwfs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great. Just a couple more changes.

Thank you for your work on this!

…ient

- rename HiveMQ related classes, variables to MQTT.

Signed-off-by: Jiandong Ma <jiandong.ma.cn@gmail.com>
@mjd507
mjd507 requested a review from cppwfs September 16, 2026 09:12

@cppwfs cppwfs left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow great work. A couple of things I noticed. Please verify and or resolve. Thank you!


@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
Assert.notNull(applicationEventPublisher, "'applicationEventPublisher' cannot be null");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to check for null. Nullify handles this for us.

.useMqttVersion3()
.willPublish(mqttClientConfig.getWillPublish().orElse(null))
.simpleAuth(mqttClientConfig.getSimpleAuth().orElse(null))
.addConnectedListener(Mqtt3ClientManager.this)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use just this. instead of Mqtt3clientManager.this

// so have to skip appending this in the new built disconnectedListener list
.automaticReconnect(inputConfig.getAutomaticReconnect().orElse(null));

if (!CollectionUtils.isEmpty(inputConfig.getConnectedListeners())) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is redundant.

builder = builder.addConnectedListener(connectedListener);
}
}
if (!CollectionUtils.isEmpty(inputConfig.getDisconnectedListeners())) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is redundant.

.withExposedPorts(HIVEMQ_PORT)
.withExposedPorts(MQTT_PORT)
.withNetwork(ToxiproxyContainerTest.NETWORK)
.withNetworkAliases("hivemq-broker");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops missed this one , we can use mqtt-broker.

protected AbstractMqttClientManager(B mqttClientBuilder) {
this.mqttClientBuilder = mqttClientBuilder;
@SuppressWarnings("this-escape")
protected AbstractMqttClientManager(C mqttClientConfig) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AbstractMqttClientManager.java:69-78 — the constructor calls the overridable buildClient(...), and both implementations pass this as a MqttClientConnectedListener (Mqtt3ClientManager.java:51, Mqtt5ClientManager.java:216). This publishes a partially constructed object: this is registered as a live callback and subclass fields are still uninitialized.

A potential fix is to have each leaf construct the client and pass it up via super(config, client) so no overridable call happens during construction.

@renechoi renechoi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Built the branch locally (Mosquitto 2.1.2).

  1. No doStop(). After adapter.stop() (isRunning() false) a publish still reached the output channel: the HiveMQ callback stays subscribed. Both Paho adapters stop delivery (MqttPahoMessageDrivenChannelAdapter:220, Mqttv5PahoMessageDrivenChannelAdapter:319) and manage a resubscribe flag; isSubscribed needs the same.

  2. The four com.hivemq.client.internal imports have public equivalents on 1.4.0: Mqtt3Connect/Mqtt5Connect/Mqtt5Disconnect.builder().build() equal the internal DEFAULTs, and Mqtt5Subscription.DEFAULT_* match.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants