This is an automated email from the ASF dual-hosted git repository. piotr pushed a commit to branch non_string_header_key in repository https://gitbox.apache.org/repos/asf/iggy.git
commit fe92af98b5644ce6cb9ce3407ed48134b7cdaa1e Author: spetz <[email protected]> AuthorDate: Thu Jan 29 21:25:05 2026 +0100 Always include user_headers in JSON response (empty array when none) --- core/common/src/types/message/iggy_message.rs | 41 +++++++++--- .../main/java/org/apache/iggy/message/Message.java | 72 ++++++++-------------- 2 files changed, 58 insertions(+), 55 deletions(-) diff --git a/core/common/src/types/message/iggy_message.rs b/core/common/src/types/message/iggy_message.rs index f34b2b272..49fe0b89b 100644 --- a/core/common/src/types/message/iggy_message.rs +++ b/core/common/src/types/message/iggy_message.rs @@ -545,24 +545,25 @@ impl Serialize for IggyMessage { use base64::{Engine as _, engine::general_purpose::STANDARD}; use serde::ser::SerializeStruct; - let field_count = 2 + self.user_headers.is_some() as usize; - - let mut state = serializer.serialize_struct("IggyMessage", field_count)?; + let mut state = serializer.serialize_struct("IggyMessage", 3)?; state.serialize_field("header", &self.header)?; let base64_payload = STANDARD.encode(&self.payload); state.serialize_field("payload", &base64_payload)?; - if self.user_headers.is_some() { + let entries: Vec<HeaderEntry> = if self.user_headers.is_some() { let headers_map = self.user_headers_map().map_err(serde::ser::Error::custom)?; if let Some(map) = headers_map { - let entries: Vec<HeaderEntry> = map - .into_iter() + map.into_iter() .map(|(key, value)| HeaderEntry { key, value }) - .collect(); - state.serialize_field("user_headers", &entries)?; + .collect() + } else { + Vec::new() } - } + } else { + Vec::new() + }; + state.serialize_field("user_headers", &entries)?; state.end() } @@ -732,6 +733,28 @@ mod tests { assert_eq!(original.payload, decoded.payload); } + #[test] + fn test_json_serialization_without_headers() { + let original = IggyMessage::builder() + .id(1) + .payload(Bytes::from("test")) + .build() + .expect("Message creation should not fail"); + + let json = serde_json::to_string(&original).expect("JSON serialization should not fail"); + + assert!(json.contains("\"user_headers\":[]")); + + let deserialized: IggyMessage = + serde_json::from_str(&json).expect("JSON deserialization should not fail"); + + assert_eq!(original.header.id, deserialized.header.id); + assert_eq!(original.payload, deserialized.payload); + + let headers_map = deserialized.user_headers_map().unwrap(); + assert!(headers_map.map(|m| m.is_empty()).unwrap_or(true)); + } + #[test] fn test_json_serialization_with_headers() { let mut headers = HashMap::new(); diff --git a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java index 4143b52b5..414062504 100644 --- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java +++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSetter; import com.fasterxml.jackson.annotation.Nulls; + import java.math.BigInteger; import java.util.Base64; import java.util.Collections; @@ -30,19 +31,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public record Message( - MessageHeader header, - byte[] payload, - Map<HeaderKey, HeaderValue> userHeaders -) { +public record Message(MessageHeader header, byte[] payload, Map<HeaderKey, HeaderValue> userHeaders) { @JsonCreator public static Message fromJson( - @JsonProperty("header") MessageHeader header, - @JsonProperty("payload") String base64Payload, - @JsonProperty(value = "user_headers", required = false) @JsonSetter( - nulls = Nulls.AS_EMPTY - ) List<HeaderEntry> userHeadersList - ) { + @JsonProperty("header") MessageHeader header, + @JsonProperty("payload") String base64Payload, + @JsonProperty(value = "user_headers", required = false) @JsonSetter(nulls = Nulls.AS_EMPTY) + List<HeaderEntry> userHeadersList) { byte[] decodedPayload = Base64.getDecoder().decode(base64Payload); Map<HeaderKey, HeaderValue> headersMap = new HashMap<>(); if (userHeadersList != null) { @@ -57,51 +52,40 @@ public record Message( return of(payload, Collections.emptyMap()); } - public static Message of( - String payload, - Map<HeaderKey, HeaderValue> userHeaders - ) { + public static Message of(String payload, Map<HeaderKey, HeaderValue> userHeaders) { final byte[] payloadBytes = payload.getBytes(); final long userHeadersLength = getUserHeadersSize(userHeaders); final MessageHeader msgHeader = new MessageHeader( - BigInteger.ZERO, - MessageId.serverGenerated(), - BigInteger.ZERO, - BigInteger.ZERO, - BigInteger.ZERO, - userHeadersLength, - (long) payloadBytes.length - ); + BigInteger.ZERO, + MessageId.serverGenerated(), + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO, + userHeadersLength, + (long) payloadBytes.length); return new Message(msgHeader, payloadBytes, userHeaders); } public Message withUserHeaders(Map<HeaderKey, HeaderValue> userHeaders) { - Map<HeaderKey, HeaderValue> mergedHeaders = mergeUserHeaders( - userHeaders - ); + Map<HeaderKey, HeaderValue> mergedHeaders = mergeUserHeaders(userHeaders); long userHeadersLength = getUserHeadersSize(mergedHeaders); MessageHeader updatedHeader = new MessageHeader( - header.checksum(), - header.id(), - header.offset(), - header.timestamp(), - header.originTimestamp(), - userHeadersLength, - (long) payload.length - ); + header.checksum(), + header.id(), + header.offset(), + header.timestamp(), + header.originTimestamp(), + userHeadersLength, + (long) payload.length); return new Message(updatedHeader, payload, mergedHeaders); } public int getSize() { long userHeadersLength = getUserHeadersSize(userHeaders); - return Math.toIntExact( - MessageHeader.SIZE + payload.length + userHeadersLength - ); + return Math.toIntExact(MessageHeader.SIZE + payload.length + userHeadersLength); } - private Map<HeaderKey, HeaderValue> mergeUserHeaders( - Map<HeaderKey, HeaderValue> userHeaders - ) { + private Map<HeaderKey, HeaderValue> mergeUserHeaders(Map<HeaderKey, HeaderValue> userHeaders) { if (userHeaders.isEmpty()) { return this.userHeaders; } @@ -110,16 +94,12 @@ public record Message( return userHeaders; } - Map<HeaderKey, HeaderValue> mergedHeaders = new HashMap<>( - this.userHeaders - ); + Map<HeaderKey, HeaderValue> mergedHeaders = new HashMap<>(this.userHeaders); mergedHeaders.putAll(userHeaders); return mergedHeaders; } - private static long getUserHeadersSize( - Map<HeaderKey, HeaderValue> userHeaders - ) { + private static long getUserHeadersSize(Map<HeaderKey, HeaderValue> userHeaders) { if (userHeaders.isEmpty()) { return 0L; }
