From 25d1378c79908bff6030a391fecb3e5beb77aded Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 17:45:19 -0500 Subject: [PATCH 1/8] Chore: Bump supported versions of Java Signed-off-by: Patrick M. Niedzielski --- .github/workflows/build.yaml | 5 +++-- pom.xml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 28b4d4d..50d5cd8 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -21,8 +21,9 @@ jobs: name: "Build & UTs: JDK ${{ matrix.Java }}" runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - java: [ '8', '11', '17' ] + java: [ '8', '11', '17', '21', '22', '23', '24', '25' ] steps: - uses: actions/checkout@v3 - uses: actions/setup-java@v3 @@ -38,7 +39,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ '8', '11', '17' ] + java: [ '8', '11', '17', '21', '25' ] steps: - uses: actions/checkout@v3 diff --git a/pom.xml b/pom.xml index 0be45bf..3baa4cc 100644 --- a/pom.xml +++ b/pom.xml @@ -268,8 +268,8 @@ limitations under the License. --> log4j older than v.2.17.1 is banned - [1.8,9),[11,12),[17,18) - Only JDK8, JDK11 and JDK17 are supported + [1.8,) + Only JDK8 or later is supported true From 8a1aa5f9df28d8cbac8c192dfb8c0a41fafe3096 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 18:11:12 -0500 Subject: [PATCH 2/8] Fix: Remove explicit JDK versioning from `SystemUtil` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it stands, our SDK only supports three old LTS versions of Java. Any user who wants to use the SDK on non-LTS versions, or on reasonably new versions of Java, will be prevented. However, what the code really wants is to know whether we’re on a version of Java before or after Java 9, with which we determine which CRC32 implementation to use. This patch *removes* explicit JDK versioning from `SystemUtil`, which is a breaking change. Signed-off-by: Patrick M. Niedzielski --- .../bloomberg/bmq/impl/infr/proto/Crc32c.java | 2 +- .../bmq/impl/infr/util/SystemUtil.java | 37 ++----------------- .../bmq/impl/infr/util/SystemUtilTest.java | 19 ---------- .../bmq/it/impl/infr/proto/Crc32cTest.java | 8 +--- 4 files changed, 6 insertions(+), 60 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Crc32c.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Crc32c.java index 3fd2242..861e4b2 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Crc32c.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/Crc32c.java @@ -32,7 +32,7 @@ public class Crc32c { // Warn if Java version > 1.8 is used. // The warning record is logged only in situation if SDK was built with // JDK8 but is used with newer one e.g. JDK11 - if (SystemUtil.getJavaVersion().compareTo(SystemUtil.JavaVersion.JAVA_8) > 0) { + if (!SystemUtil.isJava8()) { logger.warn("*** [NOTE] Starting from JDK9 switch to java.util.zip.CRC32C ***"); } } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java index d735c86..ca15210 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/util/SystemUtil.java @@ -19,7 +19,6 @@ import java.lang.invoke.MethodHandles; import java.lang.management.ManagementFactory; import java.net.ServerSocket; -import java.util.Arrays; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,40 +26,12 @@ public class SystemUtil { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - public enum JavaVersion { - JAVA_UNSUPPORTED(""), - JAVA_8("1.8"), - JAVA_11("11"), - JAVA_17("17"); - - private final String major; - - JavaVersion(String major) { - this.major = major; - } - - public boolean isSupported() { - return !major.isEmpty(); - } + public static String getJavaVersionString() { + return System.getProperty("java.version"); } - public static JavaVersion getJavaVersion() { - JavaVersion result = JavaVersion.JAVA_UNSUPPORTED; - - try { - String version = System.getProperty("java.version"); - - result = - Arrays.stream(JavaVersion.values()) - .filter(JavaVersion::isSupported) - .filter(v -> version.startsWith(v.major)) - .findFirst() - .orElse(JavaVersion.JAVA_UNSUPPORTED); - } catch (Exception e) { - logger.info("Error while getting Java version: ", e); - } - - return result; + public static boolean isJava8() { + return getJavaVersionString().startsWith("1."); } public static int getProcessId() { diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/util/SystemUtilTest.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/util/SystemUtilTest.java index 4d2600b..f7a3482 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/util/SystemUtilTest.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/impl/infr/util/SystemUtilTest.java @@ -15,7 +15,6 @@ */ package com.bloomberg.bmq.impl.infr.util; -import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.junit.jupiter.api.Assertions.assertTrue; import java.lang.invoke.MethodHandles; @@ -27,24 +26,6 @@ class SystemUtilTest { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); - @Test - void testJavaVersions() { - assertTrue( - SystemUtil.JavaVersion.JAVA_UNSUPPORTED.compareTo(SystemUtil.JavaVersion.JAVA_8) - < 0); - assertTrue(SystemUtil.JavaVersion.JAVA_8.compareTo(SystemUtil.JavaVersion.JAVA_11) < 0); - assertTrue(SystemUtil.JavaVersion.JAVA_11.compareTo(SystemUtil.JavaVersion.JAVA_17) < 0); - } - - @Test - void testVersion() { - SystemUtil.JavaVersion v = SystemUtil.getJavaVersion(); - - logger.info("JAVA ver.: {}", v); - - assertNotSame(SystemUtil.JavaVersion.JAVA_UNSUPPORTED, v); - } - @Test void testPid() { int p = SystemUtil.getProcessId(); diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/impl/infr/proto/Crc32cTest.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/impl/infr/proto/Crc32cTest.java index d23303b..13146f5 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/impl/infr/proto/Crc32cTest.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/impl/infr/proto/Crc32cTest.java @@ -17,7 +17,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import com.bloomberg.bmq.impl.infr.io.ByteBufferOutputStream; import com.bloomberg.bmq.impl.infr.proto.Crc32c; @@ -65,9 +64,6 @@ class Crc32cTest { @Test void testImplementation() { // Ensure we are running with supported version of JVM - SystemUtil.JavaVersion javaVersion = SystemUtil.getJavaVersion(); - assertTrue(javaVersion.isSupported(), "Unsupported JDK"); - boolean isPartOfJar = VersionUtil.getJarVersion() != null; if (!isPartOfJar) { @@ -81,9 +77,7 @@ void testImplementation() { // If JDK11 or above is used, then the generated JAR file also contains Java9 version of // Crc32c (native JDK implementation) and it should be used by JVM. logger.info("Running Crc32cTest as a part of Jar file"); - boolean isJava9orAbove = - SystemUtil.getJavaVersion().compareTo(SystemUtil.JavaVersion.JAVA_8) > 0; - assertEquals(isJava9orAbove, Crc32c.isJdkImplementation()); + assertEquals(SystemUtil.isJava8(), !Crc32c.isJdkImplementation()); } } From e3b7ed35221ec1afb38bcb2c87a41cd98d7ad6f2 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Tue, 2 Dec 2025 18:30:24 -0500 Subject: [PATCH 3/8] wip! Test higher jdks Signed-off-by: Patrick M. Niedzielski --- pom.xml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3baa4cc..8e7dea7 100644 --- a/pom.xml +++ b/pom.xml @@ -554,7 +554,7 @@ limitations under the License. --> If you need to support specific JDK, create new profile or update this one e.g. for JDK17 set the xml element below to 17. See version range spec for more information: https://maven.apache.org/enforcer/enforcer-rules/versionRanges.html --> - [9,) + [9,18) + + JDK18-and-above + + + [18,) + + + + 9 + + + ossrh From 1b0e592b812a17d195861585dc5e6d374cd4d1e3 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 3 Dec 2025 11:25:40 -0500 Subject: [PATCH 4/8] Fix: Avoid possible `this` escape before subclass is fully initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since Java16, we get a number of warnings of the sort [WARNING] blazingmq-sdk-java/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java:[27,25] possible 'this' escape before subclass is fully initialized These warnings are shown when a class that may serve as a superclass calls an overridable method in its constructor. If some other class inherits from that superclass and overrides that method, the overridden implementation will be called on an object that was not fully initialized. We can fix this in a few ways. On one hand, we can avoid calling methods in class constructors. This works nicely in cases like `ControlMessageChoice`, which directly forwards to an `init()` method to null out its member variables. Duplicating this code is not terrible. However, in more complicated cases, like `PutHeader` and the like, the methods we call abstract bit manupulation that’s easy to get wrong. It’s best not to inline that code in the constructors. On the other hand, we can prevent the methods we call from the class constructor from being overriden. In all cases we have this warning, there is a strong case to be made that we don’t want to allow inheritance. The message classes need to follow the protocol schema directly, and the protocol classes are also directly tied to the binary protocol that the BlazingMQ broker uses. We should not allow users to inject their own behaviors into this parsing. This patch fixes all “`this` escape” warnings that newer JDK versions give by marking the classes they’re shown for as `final`. Signed-off-by: Patrick M. Niedzielski --- .../impl/infr/msg/ControlMessageChoice.java | 70 +++++++++---------- .../infr/msg/NegotiationMessageChoice.java | 18 ++--- .../bmq/impl/infr/proto/AckMessageImpl.java | 2 +- .../bmq/impl/infr/proto/ConfirmHeader.java | 2 +- .../infr/proto/ConfirmMessageIterator.java | 2 +- .../bmq/impl/infr/proto/PushMessageImpl.java | 2 +- .../bmq/impl/infr/proto/PutHeader.java | 2 +- .../impl/infr/proto/PutMessageIterator.java | 2 +- 8 files changed, 50 insertions(+), 50 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java index d612373..e319c09 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/ControlMessageChoice.java @@ -15,7 +15,7 @@ */ package com.bloomberg.bmq.impl.infr.msg; -public class ControlMessageChoice { +public final class ControlMessageChoice { private Integer rId; private Status status; @@ -40,150 +40,150 @@ public Object createNewInstance() { return new ControlMessageChoice(); } - public final void reset() { + public void reset() { init(); } - public final void makeStatus() { + public void makeStatus() { reset(); status = new Status(); } - public final void makeOpenQueue() { + public void makeOpenQueue() { reset(); openQueue = new OpenQueue(); } - public final void makeOpenQueueResponse() { + public void makeOpenQueueResponse() { reset(); openQueueResponse = new OpenQueueResponse(); } - public final void makeConfigureQueueStream() { + public void makeConfigureQueueStream() { reset(); configureQueueStream = new ConfigureQueueStream(); } - public final void makeConfigureQueueStreamResponse() { + public void makeConfigureQueueStreamResponse() { reset(); configureQueueStreamResponse = new ConfigureQueueStreamResponse(); } - public final void makeConfigureStream() { + public void makeConfigureStream() { reset(); configureStream = new ConfigureStream(); } - public final void makeConfigureStreamResponse() { + public void makeConfigureStreamResponse() { reset(); configureStreamResponse = new ConfigureStreamResponse(); } - public final void makeCloseQueue() { + public void makeCloseQueue() { reset(); closeQueue = new CloseQueue(); } - public final void makeCloseQueueResponse() { + public void makeCloseQueueResponse() { reset(); closeQueueResponse = new CloseQueueResponse(); } - public final void makeDisconnect() { + public void makeDisconnect() { reset(); disconnect = new Disconnect(); } - public final void makeDisconnectResponse() { + public void makeDisconnectResponse() { reset(); disconnectResponse = new DisconnectResponse(); } - public final boolean isStatusValue() { + public boolean isStatusValue() { return status != null; } - public final boolean isOpenQueueValue() { + public boolean isOpenQueueValue() { return openQueue != null; } - public final boolean isOpenQueueResponseValue() { + public boolean isOpenQueueResponseValue() { return openQueueResponse != null; } - public final boolean isDisconnectValue() { + public boolean isDisconnectValue() { return disconnect != null; } - public final boolean isDisconnectResponseValue() { + public boolean isDisconnectResponseValue() { return disconnectResponse != null; } - public final boolean isConfigureQueueStreamValue() { + public boolean isConfigureQueueStreamValue() { return configureQueueStream != null; } - public final boolean isConfigureQueueStreamResponseValue() { + public boolean isConfigureQueueStreamResponseValue() { return configureQueueStreamResponse != null; } - public final boolean isConfigureStreamValue() { + public boolean isConfigureStreamValue() { return configureStream != null; } - public final boolean isConfigureStreamResponseValue() { + public boolean isConfigureStreamResponseValue() { return configureStreamResponse != null; } - public final boolean isCloseQueueValue() { + public boolean isCloseQueueValue() { return closeQueue != null; } - public final boolean isCloseQueueResponseValue() { + public boolean isCloseQueueResponseValue() { return closeQueueResponse != null; } - public final Status status() { + public Status status() { return status; } - public final OpenQueue openQueue() { + public OpenQueue openQueue() { return openQueue; } - public final OpenQueueResponse openQueueResponse() { + public OpenQueueResponse openQueueResponse() { return openQueueResponse; } - public final ConfigureQueueStream configureQueueStream() { + public ConfigureQueueStream configureQueueStream() { return configureQueueStream; } - public final ConfigureQueueStreamResponse configureQueueStreamResponse() { + public ConfigureQueueStreamResponse configureQueueStreamResponse() { return configureQueueStreamResponse; } - public final ConfigureStream configureStream() { + public ConfigureStream configureStream() { return configureStream; } - public final ConfigureStreamResponse configureStreamResponse() { + public ConfigureStreamResponse configureStreamResponse() { return configureStreamResponse; } - public final CloseQueue closeQueue() { + public CloseQueue closeQueue() { return closeQueue; } - public final CloseQueueResponse closeQueueResponse() { + public CloseQueueResponse closeQueueResponse() { return closeQueueResponse; } - public final Disconnect disconnect() { + public Disconnect disconnect() { return disconnect; } - public final DisconnectResponse disconnectResponse() { + public DisconnectResponse disconnectResponse() { return disconnectResponse; } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java index 5dd7b58..c1b71dd 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/msg/NegotiationMessageChoice.java @@ -15,7 +15,7 @@ */ package com.bloomberg.bmq.impl.infr.msg; -public class NegotiationMessageChoice { +public final class NegotiationMessageChoice { private ClientIdentity clientIdentity; private BrokerResponse brokerResponse; @@ -28,33 +28,33 @@ public Object createNewInstance() { return new NegotiationMessageChoice(); } - public final void reset() { + public void reset() { init(); } - public final void makeClientIdentity() { + public void makeClientIdentity() { reset(); clientIdentity = new ClientIdentity(); } - public final void makeBrokerResponse() { + public void makeBrokerResponse() { reset(); brokerResponse = new BrokerResponse(); } - public final boolean isClientIdentityValue() { + public boolean isClientIdentityValue() { return clientIdentity != null; } - public final boolean isBrokerResponseValue() { + public boolean isBrokerResponseValue() { return brokerResponse != null; } - public final ClientIdentity clientIdentity() { + public ClientIdentity clientIdentity() { return clientIdentity; } - public final BrokerResponse brokerResponse() { + public BrokerResponse brokerResponse() { return brokerResponse; } @@ -63,7 +63,7 @@ public void init() { brokerResponse = null; } - public final void reset(NegotiationMessageChoice copied) { + public void reset(NegotiationMessageChoice copied) { clientIdentity = copied.clientIdentity; brokerResponse = copied.brokerResponse; } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java index c86bca4..f019abb 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageImpl.java @@ -25,7 +25,7 @@ import com.bloomberg.bmq.impl.infr.util.BitUtil; import java.io.IOException; -public class AckMessageImpl implements Streamable { +public final class AckMessageImpl implements Streamable { // This class defines the (repeated) payload following the 'AckHeader' // struct. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java index addbcfd..146abf7 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmHeader.java @@ -21,7 +21,7 @@ import com.bloomberg.bmq.impl.infr.util.BitUtil; import java.io.IOException; -public class ConfirmHeader implements Streamable { +public final class ConfirmHeader implements Streamable { // This class represents header for a 'CONFIRM' event. A 'CONFIRM' event // is the event sent by a client to the broker to signify it's done // processing a specific message and the broker can dispose of it. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java index 666402a..27a2542 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/ConfirmMessageIterator.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class ConfirmMessageIterator extends MessageIterator { +public final class ConfirmMessageIterator extends MessageIterator { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java index 26c4dc4..da86892 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageImpl.java @@ -26,7 +26,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PushMessageImpl implements Streamable { +public final class PushMessageImpl implements Streamable { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java index 9d73b90..0a63a9f 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutHeader.java @@ -22,7 +22,7 @@ import com.bloomberg.bmq.impl.infr.util.BitUtil; import java.io.IOException; -public class PutHeader { +public final class PutHeader { // This class represents the header for a 'PUT' event. A 'PUT' event is // the event sent by a client to the broker to post message on queue(s). diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java index 7194c8c..889fa16 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PutMessageIterator.java @@ -21,7 +21,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PutMessageIterator extends MessageIterator implements Iterator { +public final class PutMessageIterator extends MessageIterator implements Iterator { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); From 0cf335b7f290ab4f272b13434dc9b2507f16df81 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 3 Dec 2025 11:58:42 -0500 Subject: [PATCH 5/8] Fix: avoid implicit cast from `int` to `byte` Compiling on modern JDKs results in the following warning: blazingmq-sdk-java/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java:[255,31] implicit cast from int to byte in compound assignment is possibly lossy This patch fixes this warning by making the cast explicit. In Java all bitshift operations result in integral types like `int` or `long`, never `byte`. So, even though we guarantee that the result of our bitshift operation must fit within eight bits, its type is `int`. To silence the warning, we make the cast explicit. Signed-off-by: Patrick M. Niedzielski --- .../java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java index e89e4e5..8f175cb 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java @@ -252,7 +252,7 @@ public void setControlEventEncodingType(EncodingType type) { byte typeAsByte = (byte) (type.toInt()); // Set those bits to represent 'type' - typeSpecificUpdate |= (typeAsByte << CONTROL_EVENT_ENCODING_START_IDX); + typeSpecificUpdate |= (byte) (typeAsByte << CONTROL_EVENT_ENCODING_START_IDX); setTypeSpecific(typeSpecificUpdate); } From 4c42a4e7fa5d1c4dd5e984119db79bbbad1a73a2 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 3 Dec 2025 12:13:19 -0500 Subject: [PATCH 6/8] Fix: avoid implicit cast from `long` to `int` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling on modern JDKs results in the following warning: [WARNING] blazingmq-sdk-java/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java:[234,24] implicit cast from long to int in compound assignment is possibly lossy This is fired on the line: // Add padding bytes totalLength += numPaddingBytes; where `totalLength` is an `int` and `numPaddingBytes` is a `long`. However, `numPaddingBytes` is initialized few lines above as // Read padding bytes final long numPaddingBytes = input.readByte(); Since `readByte()` returns a `byte`, there’s no reason for this constant to be `long`. This patch fixes the above warning by avoiding the needless conversion to `long`. Signed-off-by: Patrick M. Niedzielski --- .../bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java index bc5f634..00a1ca0 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesImpl.java @@ -216,7 +216,7 @@ public int streamInOld(T input) throws IOExc } // Read padding bytes - final long numPaddingBytes = input.readByte(); + final byte numPaddingBytes = input.readByte(); // Skip padding bytes if (input.skip(numPaddingBytes - 1) != numPaddingBytes - 1) { From 7d703975f043d54ef7f96f53e4993d34b184dd05 Mon Sep 17 00:00:00 2001 From: "Patrick M. Niedzielski" Date: Wed, 3 Dec 2025 13:02:26 -0500 Subject: [PATCH 7/8] wip! this escape --- .../com/bloomberg/bmq/impl/infr/proto/AckEventImpl.java | 3 +++ .../java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java | 2 +- .../bloomberg/bmq/impl/infr/proto/AckMessageIterator.java | 2 ++ .../bmq/impl/infr/proto/BinaryMessageProperty.java | 1 + .../bloomberg/bmq/impl/infr/proto/BoolMessageProperty.java | 1 + .../bloomberg/bmq/impl/infr/proto/ByteMessageProperty.java | 1 + .../com/bloomberg/bmq/impl/infr/proto/EventBuilder.java | 2 +- .../java/com/bloomberg/bmq/impl/infr/proto/EventHeader.java | 2 +- .../bloomberg/bmq/impl/infr/proto/Int32MessageProperty.java | 1 + .../bloomberg/bmq/impl/infr/proto/Int64MessageProperty.java | 1 + .../com/bloomberg/bmq/impl/infr/proto/MessageIterator.java | 6 +++--- .../bmq/impl/infr/proto/MessagePropertiesHeader.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/MessageProperty.java | 2 +- .../com/bloomberg/bmq/impl/infr/proto/OptionHeader.java | 2 +- .../java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java | 2 +- .../bloomberg/bmq/impl/infr/proto/PushMessageIterator.java | 1 + .../bloomberg/bmq/impl/infr/proto/ShortMessageProperty.java | 1 + .../bmq/impl/infr/proto/StringMessageProperty.java | 1 + 18 files changed, 23 insertions(+), 10 deletions(-) diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckEventImpl.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckEventImpl.java index c059145..225bc20 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckEventImpl.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckEventImpl.java @@ -26,6 +26,9 @@ public class AckEventImpl extends EventImpl { final AckHeader header; final Collection messages = new ArrayList<>(); + @SuppressWarnings( + "this-escape") // passing `this` to `AckMessageIterator` is necessary to fully construct + // `this` public AckEventImpl(ByteBuffer[] bbuf) { super(EventType.ACK, bbuf); AckMessageIterator it = new AckMessageIterator(this); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java index 11e07ed..d8ac63b 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckHeader.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class AckHeader implements Streamable { +public final class AckHeader implements Streamable { // This class represents header for an 'ACK' event. An 'ACK' event is the // event sent by the broker to a client in response to a post message on // queue. Such event is optional, depending on flags used at queue open. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java index 096dcf0..e730750 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/AckMessageIterator.java @@ -28,6 +28,8 @@ public class AckMessageIterator extends MessageIterator implements Iterator T fetchNextMessage(T message) { + protected final T fetchNextMessage(T message) { Argument.expectNonNull(message, "message"); try { if (currentPosition > 0) { @@ -65,7 +65,7 @@ protected T fetchNextMessage(T message) { } } - public boolean isValid() { + public final boolean isValid() { return event != null; } } diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesHeader.java index 4fcca7f..e31cf68 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessagePropertiesHeader.java @@ -21,7 +21,7 @@ import java.io.DataOutput; import java.io.IOException; -public class MessagePropertiesHeader { +public final class MessagePropertiesHeader { // This class represents the header for message properties area in a PUT // or PUSH message. This header will be followed by one or more message // properties. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessageProperty.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessageProperty.java index 7eb924a..19146d9 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessageProperty.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/MessageProperty.java @@ -34,7 +34,7 @@ public void setPropertyName(String name) { propertyName = name; } - public void setPropertyValue(byte[] val) { + public final void setPropertyValue(byte[] val) { Argument.expectNonNull(val, "val"); Argument.expectNotGreater(val.length, maxValueSize, "property length"); propertyValue = Arrays.copyOf(val, val.length); diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java index 5266b50..0ed4078 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/OptionHeader.java @@ -25,7 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OptionHeader implements Streamable { +public final class OptionHeader implements Streamable { // This class represents the header for an option. In a typical // implementation usage, every Option class will start by an // 'OptionHeader' member. diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java index f6c66cb..cde2350 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushHeader.java @@ -24,7 +24,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PushHeader { +public final class PushHeader { static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); // This struct represents the header for a 'PUSH' event. A 'PUSH' event is diff --git a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java index 181e612..ed46486 100644 --- a/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java +++ b/bmq-sdk/src/main/java/com/bloomberg/bmq/impl/infr/proto/PushMessageIterator.java @@ -27,6 +27,7 @@ public class PushMessageIterator extends MessageIterator implements Iterator Date: Wed, 3 Dec 2025 16:11:44 -0500 Subject: [PATCH 8/8] wip! suppress cast warning [WARNING] blazingmq-sdk-java/bmq-sdk/src/test/java/com/bloomberg/bmq/it/util/TestTools.java:[152,16] redundant cast to java.nio.ByteBuffer Signed-off-by: Patrick M. Niedzielski --- .../src/test/java/com/bloomberg/bmq/it/util/TestTools.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/util/TestTools.java b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/util/TestTools.java index 48852a8..8cdfaab 100644 --- a/bmq-sdk/src/test/java/com/bloomberg/bmq/it/util/TestTools.java +++ b/bmq-sdk/src/test/java/com/bloomberg/bmq/it/util/TestTools.java @@ -146,10 +146,9 @@ public static ByteBuffer mergeBuffers(ByteBuffer[] bbuf) { for (ByteBuffer b : bbuf) { bb.put(b); } + bb.flip(); - // 'flip()' might return 'Buffer' interface objects in some JDKs, - // need to specify concrete class - return (ByteBuffer) bb.flip(); + return bb; } public static PutMessageImpl preparePutMessage(String payload, boolean isOldStyleProperties)