From 2b6cafdba4c05d69d4ec7c640ab4eba030bba3ee Mon Sep 17 00:00:00 2001 From: Nathan Kurtyka Date: Thu, 22 Mar 2018 11:49:46 -0400 Subject: [PATCH] INT-4440: Support serialized UUID in headers JIRA: https://jira.spring.io/browse/INT-4440 The previous fix eliminated an extra `generateId()` call, but at the same introduced regression do not populate `id` and `timestamp` from the serialized state, e.g. after JSON transferring over the network * Introduce a couple utility methods in the `MutableMessageHeaders` to extract and parse `id` and `timestamp` from the provided headers **Cherry-pick to 5.0.x** (cherry picked from commit ae2aa8b) --- .../support/MutableMessageHeaders.java | 43 +++++++++++++++---- .../support/MutableMessageTests.java | 43 +++++++++++++++++-- 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/support/MutableMessageHeaders.java b/spring-integration-core/src/main/java/org/springframework/integration/support/MutableMessageHeaders.java index c6b58ad9ea..318fc38993 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/support/MutableMessageHeaders.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/support/MutableMessageHeaders.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2017 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.integration.support; +import java.nio.ByteBuffer; import java.util.Map; import java.util.UUID; @@ -30,6 +31,7 @@ import org.springframework.messaging.MessageHeaders; * @author Stuart Williams * @author David Turanski * @author Artem Bilan + * @author Nathan Kurtyka * * @since 4.2 */ @@ -38,16 +40,12 @@ public class MutableMessageHeaders extends MessageHeaders { private static final long serialVersionUID = 3084692953798643018L; public MutableMessageHeaders(@Nullable Map headers) { - this(headers, - (headers != null ? - (UUID) headers.get(MessageHeaders.ID) - : null), - (headers != null ? - (Long) headers.get(MessageHeaders.TIMESTAMP) - : null)); + super(headers, extractId(headers), extractTimestamp(headers)); } - protected MutableMessageHeaders(@Nullable Map headers, @Nullable UUID id, @Nullable Long timestamp) { + protected MutableMessageHeaders(@Nullable Map headers, @Nullable UUID id, + @Nullable Long timestamp) { + super(headers, id, timestamp); } @@ -76,4 +74,31 @@ public class MutableMessageHeaders extends MessageHeaders { return super.getRawHeaders().remove(key); } + private static UUID extractId(@Nullable Map headers) { + if (headers != null && headers.containsKey(MessageHeaders.ID)) { + Object id = headers.get(MessageHeaders.ID); + if (id instanceof String) { + return UUID.fromString((String) id); + } + else if (id instanceof byte[]) { + ByteBuffer bb = ByteBuffer.wrap((byte[]) id); + return new UUID(bb.getLong(), bb.getLong()); + } + else { + return (UUID) id; + } + } + + return null; + } + + private static Long extractTimestamp(@Nullable Map headers) { + if (headers != null && headers.containsKey(MessageHeaders.TIMESTAMP)) { + Object timestamp = headers.get(MessageHeaders.TIMESTAMP); + return (timestamp instanceof String) ? Long.parseLong((String) timestamp) : (Long) timestamp; + } + + return null; + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/support/MutableMessageTests.java b/spring-integration-core/src/test/java/org/springframework/integration/support/MutableMessageTests.java index 432a8c3c8d..efc3cbbee6 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/support/MutableMessageTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/support/MutableMessageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015-2016 the original author or authors. + * Copyright 2015-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,8 +17,10 @@ package org.springframework.integration.support; import static org.hamcrest.Matchers.hasEntry; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -30,6 +32,8 @@ import org.springframework.messaging.MessageHeaders; /** * @author Stuart Williams + * @author Nathan Kurtyka + * * @since 4.2 */ public class MutableMessageTests { @@ -49,8 +53,8 @@ public class MutableMessageTests { MutableMessage mutableMessage = new MutableMessage<>(payload, headerMap); MutableMessageHeaders headers = mutableMessage.getHeaders(); - assertThat(headers.getRawHeaders(), hasEntry(MessageHeaders.ID, (Object) uuid)); - assertThat(headers.getRawHeaders(), hasEntry(MessageHeaders.TIMESTAMP, (Object) timestamp)); + assertThat(headers.getRawHeaders(), hasEntry(MessageHeaders.ID, uuid)); + assertThat(headers.getRawHeaders(), hasEntry(MessageHeaders.TIMESTAMP, timestamp)); } @Test @@ -69,7 +73,38 @@ public class MutableMessageTests { headers.remove("eep"); headers.putAll(additional); - assertThat(headers.getRawHeaders(), hasEntry("foo", (Object) "bar")); + assertThat(headers.getRawHeaders(), hasEntry("foo", "bar")); + } + + @Test + public void testMessageHeaderIsSerializable() { + + Object payload = new Object(); + + UUID uuid = UUID.nameUUIDFromBytes(((System.currentTimeMillis() - System.nanoTime()) + "").getBytes()); + Long timestamp = System.currentTimeMillis(); + + // UUID as String; timestamp as String + Map headerMapStrings = new HashMap<>(); + headerMapStrings.put(MessageHeaders.ID, uuid.toString()); + headerMapStrings.put(MessageHeaders.TIMESTAMP, timestamp.toString()); + MutableMessage mutableMessageStrings = new MutableMessage<>(payload, headerMapStrings); + assertEquals(uuid, mutableMessageStrings.getHeaders().getId()); + assertEquals(timestamp, mutableMessageStrings.getHeaders().getTimestamp()); + + // UUID as byte[]; timestamp as Long + Map headerMapByte = new HashMap<>(); + byte[] uuidAsBytes = + ByteBuffer.allocate(16) + .putLong(uuid.getMostSignificantBits()) + .putLong(uuid.getLeastSignificantBits()) + .array(); + + headerMapByte.put(MessageHeaders.ID, uuidAsBytes); + headerMapByte.put(MessageHeaders.TIMESTAMP, timestamp); + MutableMessage mutableMessageBytes = new MutableMessage<>(payload, headerMapByte); + assertEquals(uuid, mutableMessageBytes.getHeaders().getId()); + assertEquals(timestamp, mutableMessageBytes.getHeaders().getTimestamp()); } }