Skip to content

Commit 66338d6

Browse files
committed
DATAREDIS-1212 Add helper methods to Message to avoid allocation in DefaultMessage
1 parent 3022efa commit 66338d6

File tree

6 files changed

+147
-9
lines changed

6 files changed

+147
-9
lines changed

src/main/java/org/springframework/data/redis/connection/DefaultMessage.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,17 @@
1515
*/
1616
package org.springframework.data.redis.connection;
1717

18+
import org.springframework.data.redis.connection.util.ByteArrayWrapper;
1819
import org.springframework.lang.Nullable;
1920
import org.springframework.util.Assert;
21+
import org.springframework.util.ObjectUtils;
2022

2123
/**
2224
* Default message implementation.
2325
*
2426
* @author Costin Leau
2527
* @author Christoph Strobl
28+
* @author Thomas Heigl
2629
*/
2730
public class DefaultMessage implements Message {
2831

@@ -39,9 +42,6 @@ public DefaultMessage(byte[] channel, byte[] body) {
3942
this.channel = channel;
4043
}
4144

42-
/**
43-
* @return
44-
*/
4545
public byte[] getChannel() {
4646
return channel.clone();
4747
}
@@ -50,9 +50,28 @@ public byte[] getBody() {
5050
return body.clone();
5151
}
5252

53+
public boolean hasChannel() {
54+
return !ObjectUtils.isEmpty(channel);
55+
}
56+
57+
public boolean hasBody() {
58+
return !ObjectUtils.isEmpty(body);
59+
}
60+
61+
public String getChannelAsString() {
62+
return new String(channel);
63+
}
64+
65+
public String getBodyAsString() {
66+
return new String(body);
67+
}
68+
69+
public ByteArrayWrapper getChannelAsWrapper() {
70+
return new ByteArrayWrapper(channel);
71+
}
72+
5373
@Override
5474
public String toString() {
55-
5675
if (toString == null) {
5776
toString = new String(body);
5877
}

src/main/java/org/springframework/data/redis/connection/Message.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717

1818
import java.io.Serializable;
1919

20-
import org.springframework.lang.Nullable;
20+
import org.springframework.data.redis.connection.util.ByteArrayWrapper;
21+
import org.springframework.util.ObjectUtils;
2122

2223
/**
2324
* Class encapsulating a Redis message body and its properties.
2425
*
2526
* @author Costin Leau
2627
* @author Christoph Strobl
28+
* @author Thomas Heigl
2729
*/
2830
public interface Message extends Serializable {
2931

@@ -40,4 +42,50 @@ public interface Message extends Serializable {
4042
* @return message channel. Never {@literal null}.
4143
*/
4244
byte[] getChannel();
45+
46+
/**
47+
* Check if the message has a channel
48+
*
49+
* @return {@code true} if the message has a channel, otherwise {@code false}
50+
*/
51+
default boolean hasChannel() {
52+
return !ObjectUtils.isEmpty(getChannel());
53+
}
54+
55+
/**
56+
* Check if the message has a body
57+
*
58+
* @return {@code true} if the message has a body, otherwise {@code false}
59+
*/
60+
default boolean hasBody() {
61+
return !ObjectUtils.isEmpty(getBody());
62+
}
63+
64+
/**
65+
* Returns the string representation of the channel associated with the message.
66+
*
67+
* @return message channel as string. Never {@literal null}.
68+
*/
69+
default String getChannelAsString() {
70+
return new String(getChannel());
71+
}
72+
73+
/**
74+
* Returns the string representation of the body (or the payload) of the message
75+
*
76+
* @return body as string. Never {@literal null}.
77+
*/
78+
default String getBodyAsString() {
79+
return new String(getBody());
80+
}
81+
82+
/**
83+
* Returns the channel associated with the message wrapped in a {@link ByteArrayWrapper}
84+
*
85+
* @return the wrapped channel
86+
*/
87+
default ByteArrayWrapper getChannelAsWrapper() {
88+
return new ByteArrayWrapper(getChannel());
89+
}
90+
4391
}

src/main/java/org/springframework/data/redis/core/RedisKeyValueAdapter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,7 @@ public void onMessage(Message message, @Nullable byte[] pattern) {
808808

809809
Object value = CollectionUtils.isEmpty(hash) ? null : converter.read(Object.class, new RedisData(hash));
810810

811-
String channel = !ObjectUtils.isEmpty(message.getChannel())
811+
String channel = message.hasChannel()
812812
? converter.getConversionService().convert(message.getChannel(), String.class)
813813
: null;
814814

@@ -826,7 +826,7 @@ public void onMessage(Message message, @Nullable byte[] pattern) {
826826

827827
private boolean isKeyExpirationMessage(Message message) {
828828

829-
if (message == null || message.getChannel() == null || message.getBody() == null) {
829+
if (message == null || !message.hasChannel() || !message.hasBody()) {
830830
return false;
831831
}
832832

src/main/java/org/springframework/data/redis/listener/KeyspaceEventMessageListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public KeyspaceEventMessageListener(RedisMessageListenerContainer listenerContai
6060
@Override
6161
public void onMessage(Message message, @Nullable byte[] pattern) {
6262

63-
if (message == null || ObjectUtils.isEmpty(message.getChannel()) || ObjectUtils.isEmpty(message.getBody())) {
63+
if (message == null || !message.hasChannel() || !message.hasBody()) {
6464
return;
6565
}
6666

src/main/java/org/springframework/data/redis/listener/RedisMessageListenerContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ public void onMessage(Message message, @Nullable byte[] pattern) {
970970
} else {
971971
pattern = null;
972972
// do channel matching first
973-
listeners = channelMapping.get(new ByteArrayWrapper(message.getChannel()));
973+
listeners = channelMapping.get(message.getChannelAsWrapper());
974974
}
975975

976976
if (!CollectionUtils.isEmpty(listeners)) {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.connection;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.data.redis.connection.util.ByteArrayWrapper;
22+
23+
/**
24+
* @author Thomas Heigl
25+
*/
26+
class DefaultMessageTest {
27+
28+
private static final String CHANNEL = "AnyChannel";
29+
private static final String BODY = "AnyBody";
30+
private static final byte[] EMPTY_BYTES = {};
31+
private static final byte[] CHANNEL_BYTES = CHANNEL.getBytes();
32+
private static final byte[] BODY_BYTES = BODY.getBytes();
33+
34+
@Test
35+
void testHasChannel() {
36+
assertThat(aMessageWithChannel(EMPTY_BYTES).hasChannel()).isFalse();
37+
assertThat(aMessageWithChannel(CHANNEL_BYTES).hasChannel()).isTrue();
38+
}
39+
40+
@Test
41+
void testHasBody() {
42+
assertThat(aMessageWithBody(EMPTY_BYTES).hasBody()).isFalse();
43+
assertThat(aMessageWithBody(CHANNEL_BYTES).hasBody()).isTrue();
44+
}
45+
46+
@Test
47+
void testGetChannelAsString() {
48+
assertThat(aMessageWithChannel(EMPTY_BYTES).getChannelAsString()).isEmpty();
49+
assertThat(aMessageWithChannel(CHANNEL_BYTES).getChannelAsString()).isEqualTo(CHANNEL);
50+
}
51+
52+
@Test
53+
void testGetBodyAsString() {
54+
assertThat(aMessageWithBody(EMPTY_BYTES).getBodyAsString()).isEmpty();
55+
assertThat(aMessageWithBody(BODY_BYTES).getBodyAsString()).isEqualTo(BODY);
56+
}
57+
58+
@Test
59+
void testGetChannelAsWrapper() {
60+
assertThat(aMessageWithChannel(EMPTY_BYTES).getChannelAsWrapper()).isEqualTo(new ByteArrayWrapper(EMPTY_BYTES));
61+
assertThat(aMessageWithChannel(CHANNEL_BYTES).getChannelAsWrapper()).isEqualTo(new ByteArrayWrapper(CHANNEL_BYTES));
62+
}
63+
64+
private DefaultMessage aMessageWithChannel(byte[] channel) {
65+
return new DefaultMessage(channel, EMPTY_BYTES);
66+
}
67+
68+
private DefaultMessage aMessageWithBody(byte[] body) {
69+
return new DefaultMessage(EMPTY_BYTES, body);
70+
}
71+
}

0 commit comments

Comments
 (0)