Skip to content

Commit 4b9c3fa

Browse files
committed
Polishing Javadoc
See gh-25821
1 parent b322cbd commit 4b9c3fa

File tree

3 files changed

+103
-92
lines changed

3 files changed

+103
-92
lines changed

spring-messaging/src/main/java/org/springframework/messaging/support/MessageHeaderAccessor.java

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,76 +39,62 @@
3939
import org.springframework.util.StringUtils;
4040

4141
/**
42-
* A base for classes providing strongly typed getters and setters as well as
43-
* behavior around specific categories of headers (e.g. STOMP headers).
44-
* Supports creating new headers, modifying existing headers (when still mutable),
45-
* or copying and modifying existing headers.
46-
*
47-
* <p>The method {@link #getMessageHeaders()} provides access to the underlying,
48-
* fully-prepared {@link MessageHeaders} that can then be used as-is (i.e.
49-
* without copying) to create a single message as follows:
42+
* Wrapper around {@link MessageHeaders} that provides extra features such as
43+
* strongly typed accessors for specific headers, the ability to leave headers
44+
* in a {@link Message} mutable, and the option to suppress automatic generation
45+
* of {@link MessageHeaders#ID id} and {@link MessageHeaders#TIMESTAMP
46+
* timesteamp} headers. Sub-classes such as {@link NativeMessageHeaderAccessor}
47+
* and others provide support for managing processing vs external source headers
48+
* as well as protocol specific headers.
5049
*
50+
* <p>Below is a workflow to initialize headers via {@code MessageHeaderAccessor},
51+
* or one of its sub-classes, then create a {@link Message}, and then re-obtain
52+
* the accessor possibly from a different component:
5153
* <pre class="code">
54+
* // Create a message with headers
5255
* MessageHeaderAccessor accessor = new MessageHeaderAccessor();
5356
* accessor.setHeader("foo", "bar");
54-
* Message message = MessageBuilder.createMessage("payload", accessor.getMessageHeaders());
55-
* </pre>
57+
* MessageHeaders headers = accessor.getMessageHeaders();
58+
* Message message = MessageBuilder.createMessage("payload", headers);
5659
*
57-
* <p>After the above, by default the {@code MessageHeaderAccessor} becomes
58-
* immutable. However it is possible to leave it mutable for further initialization
59-
* in the same thread, for example:
60+
* // Later on
61+
* MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message);
62+
* Assert.notNull(accessor, "No MessageHeaderAccessor");
63+
* </pre>
6064
*
65+
* <p>In order for the above to work, all participating components must use
66+
* {@code MessageHeaders} to create, access, or modify headers, or otherwise
67+
* {@link MessageHeaderAccessor#getAccessor(Message, Class)} will return null.
68+
* Below is a workflow that shows how headers are created and left mutable,
69+
* then modified possibly by a different component, and finally made immutable
70+
* perhaps before the possibility of being accessed on a different thread:
6171
* <pre class="code">
72+
* // Create a message with mutable headers
6273
* MessageHeaderAccessor accessor = new MessageHeaderAccessor();
6374
* accessor.setHeader("foo", "bar");
6475
* accessor.setLeaveMutable(true);
65-
* Message message = MessageBuilder.createMessage("payload", accessor.getMessageHeaders());
76+
* MessageHeaders headers = accessor.getMessageHeaders();
77+
* Message message = MessageBuilder.createMessage("payload", headers);
6678
*
67-
* // later on in the same thread...
79+
* // Later on
80+
* MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message);
81+
* if (accessor.isMutable()) {
82+
* // It's mutable, just change the headers
83+
* accessor.setHeader("bar", "baz");
84+
* }
85+
* else {
86+
* // It's not, so get a mutable copy, change and re-create
87+
* accessor = MessageHeaderAccessor.getMutableAccessor(message);
88+
* accessor.setHeader("bar", "baz");
89+
* accessor.setLeaveMutable(true); // leave mutable again or not?
90+
* message = MessageBuilder.createMessage(message.getPayload(), accessor);
91+
* }
6892
*
93+
* // Make the accessor immutable
6994
* MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message);
70-
* accessor.setHeader("bar", "baz");
7195
* accessor.setImmutable();
7296
* </pre>
7397
*
74-
* <p>The method {@link #toMap()} returns a copy of the underlying headers. It can
75-
* be used to prepare multiple messages from the same {@code MessageHeaderAccessor}
76-
* instance:
77-
* <pre class="code">
78-
* MessageHeaderAccessor accessor = new MessageHeaderAccessor();
79-
* MessageBuilder builder = MessageBuilder.withPayload("payload").setHeaders(accessor);
80-
*
81-
* accessor.setHeader("foo", "bar1");
82-
* Message message1 = builder.build();
83-
*
84-
* accessor.setHeader("foo", "bar2");
85-
* Message message2 = builder.build();
86-
*
87-
* accessor.setHeader("foo", "bar3");
88-
* Message message3 = builder.build();
89-
* </pre>
90-
*
91-
* <p>However note that with the above style, the header accessor is shared and
92-
* cannot be re-obtained later on. Alternatively it is also possible to create
93-
* one {@code MessageHeaderAccessor} per message:
94-
*
95-
* <pre class="code">
96-
* MessageHeaderAccessor accessor1 = new MessageHeaderAccessor();
97-
* accessor.set("foo", "bar1");
98-
* Message message1 = MessageBuilder.createMessage("payload", accessor1.getMessageHeaders());
99-
*
100-
* MessageHeaderAccessor accessor2 = new MessageHeaderAccessor();
101-
* accessor.set("foo", "bar2");
102-
* Message message2 = MessageBuilder.createMessage("payload", accessor2.getMessageHeaders());
103-
*
104-
* MessageHeaderAccessor accessor3 = new MessageHeaderAccessor();
105-
* accessor.set("foo", "bar3");
106-
* Message message3 = MessageBuilder.createMessage("payload", accessor3.getMessageHeaders());
107-
* </pre>
108-
*
109-
* <p>Note that the above examples aim to demonstrate the general idea of using
110-
* header accessors. The most likely usage however is through subclasses.
111-
*
11298
* @author Rossen Stoyanchev
11399
* @author Juergen Hoeller
114100
* @since 4.0
@@ -568,6 +554,21 @@ public String toString() {
568554

569555
// Static factory methods
570556

557+
/**
558+
* Return the original {@code MessageHeaderAccessor} used to create the headers
559+
* of the given {@code Message}, or {@code null} if that's not available or if
560+
* its type does not match the required type.
561+
* <p>This is for cases where the existence of an accessor is strongly expected
562+
* (followed up with an assertion) or where an accessor will be created otherwise.
563+
* @param message the message to get an accessor for
564+
* @return an accessor instance of the specified type, or {@code null} if none
565+
* @since 5.1.19
566+
*/
567+
@Nullable
568+
public static MessageHeaderAccessor getAccessor(Message<?> message) {
569+
return getAccessor(message.getHeaders(), null);
570+
}
571+
571572
/**
572573
* Return the original {@code MessageHeaderAccessor} used to create the headers
573574
* of the given {@code Message}, or {@code null} if that's not available or if
@@ -627,6 +628,11 @@ public static MessageHeaderAccessor getMutableAccessor(Message<?> message) {
627628
}
628629

629630

631+
/**
632+
* Extension of {@link MessageHeaders} that helps to preserve the link to
633+
* the outer {@link MessageHeaderAccessor} instance that created it as well
634+
* as keeps track of whether headers are still mutable.
635+
*/
630636
@SuppressWarnings("serial")
631637
private class MutableMessageHeaders extends MessageHeaders {
632638

spring-messaging/src/main/java/org/springframework/messaging/support/NativeMessageHeaderAccessor.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,40 +30,34 @@
3030
import org.springframework.util.ObjectUtils;
3131

3232
/**
33-
* An extension of {@link MessageHeaderAccessor} that also stores and provides read/write
34-
* access to message headers from an external source -- e.g. a Spring {@link Message}
35-
* created to represent a STOMP message received from a STOMP client or message broker.
36-
* Native message headers are kept in a {@code Map<String, List<String>>} under the key
37-
* {@link #NATIVE_HEADERS}.
33+
* {@link MessageHeaderAccessor} sub-class that supports storage and access of
34+
* headers from an external source such as a message broker. Headers from the
35+
* external source are kept separate from other headers, in a sub-map under the
36+
* key {@link #NATIVE_HEADERS}. This allows separating processing headers from
37+
* headers that need to be sent to or received from the external source.
3838
*
39-
* <p>This class is not intended for direct use but is rather expected to be used
40-
* indirectly through protocol-specific sub-classes such as
41-
* {@link org.springframework.messaging.simp.stomp.StompHeaderAccessor StompHeaderAccessor}.
42-
* Such sub-classes may provide factory methods to translate message headers from
43-
* an external messaging source (e.g. STOMP) to Spring {@link Message} headers and
44-
* reversely to translate Spring {@link Message} headers to a message to send to an
45-
* external source.
39+
* <p>This class is likely to be used through indirectly through a protocol
40+
* specific sub-class that also provide factory methods to translate
41+
* message headers to an from an external messaging source.
4642
*
4743
* @author Rossen Stoyanchev
4844
* @since 4.0
4945
*/
5046
public class NativeMessageHeaderAccessor extends MessageHeaderAccessor {
5147

52-
/**
53-
* The header name used to store native headers.
54-
*/
48+
/** The header name used to store native headers. */
5549
public static final String NATIVE_HEADERS = "nativeHeaders";
5650

5751

5852
/**
59-
* A protected constructor to create new headers.
53+
* Protected constructor to create a new instance.
6054
*/
6155
protected NativeMessageHeaderAccessor() {
6256
this((Map<String, List<String>>) null);
6357
}
6458

6559
/**
66-
* A protected constructor to create new headers.
60+
* Protected constructor to create an instance with the given native headers.
6761
* @param nativeHeaders native headers to create the message with (may be {@code null})
6862
*/
6963
protected NativeMessageHeaderAccessor(@Nullable Map<String, List<String>> nativeHeaders) {
@@ -73,7 +67,7 @@ protected NativeMessageHeaderAccessor(@Nullable Map<String, List<String>> native
7367
}
7468

7569
/**
76-
* A protected constructor accepting the headers of an existing message to copy.
70+
* Protected constructor that copies headers from another message.
7771
*/
7872
protected NativeMessageHeaderAccessor(@Nullable Message<?> message) {
7973
super(message);
@@ -88,14 +82,18 @@ protected NativeMessageHeaderAccessor(@Nullable Message<?> message) {
8882
}
8983
}
9084

85+
86+
/**
87+
* Sub-classes can use this method to access the "native" headers sub-map.
88+
*/
9189
@SuppressWarnings("unchecked")
9290
@Nullable
9391
protected Map<String, List<String>> getNativeHeaders() {
9492
return (Map<String, List<String>>) getHeader(NATIVE_HEADERS);
9593
}
9694

9795
/**
98-
* Return a copy of the native header values or an empty map.
96+
* Return a copy of the native headers sub-map, or an empty map.
9997
*/
10098
public Map<String, List<String>> toNativeHeaderMap() {
10199
Map<String, List<String>> map = getNativeHeaders();
@@ -124,8 +122,7 @@ public boolean containsNativeHeader(String headerName) {
124122
}
125123

126124
/**
127-
* Return all values for the specified native header.
128-
* or {@code null} if none.
125+
* Return the values for the specified native header, if present.
129126
*/
130127
@Nullable
131128
public List<String> getNativeHeader(String headerName) {
@@ -134,8 +131,7 @@ public List<String> getNativeHeader(String headerName) {
134131
}
135132

136133
/**
137-
* Return the first value for the specified native header,
138-
* or {@code null} if none.
134+
* Return the first value for the specified native header, if present.
139135
*/
140136
@Nullable
141137
public String getFirstNativeHeader(String headerName) {
@@ -151,6 +147,8 @@ public String getFirstNativeHeader(String headerName) {
151147

152148
/**
153149
* Set the specified native header value replacing existing values.
150+
* <p>In order for this to work, the accessor must be {@link #isMutable()
151+
* mutable}. See {@link MessageHeaderAccessor} for details.
154152
*/
155153
public void setNativeHeader(String name, @Nullable String value) {
156154
Assert.state(isMutable(), "Already immutable");
@@ -176,6 +174,8 @@ public void setNativeHeader(String name, @Nullable String value) {
176174

177175
/**
178176
* Add the specified native header value to existing values.
177+
* <p>In order for this to work, the accessor must be {@link #isMutable()
178+
* mutable}. See {@link MessageHeaderAccessor} for details.
179179
*/
180180
public void addNativeHeader(String name, @Nullable String value) {
181181
Assert.state(isMutable(), "Already immutable");
@@ -199,6 +199,11 @@ public void addNativeHeaders(@Nullable MultiValueMap<String, String> headers) {
199199
headers.forEach((key, values) -> values.forEach(value -> addNativeHeader(key, value)));
200200
}
201201

202+
/**
203+
* Remove the specified native header value replacing existing values.
204+
* <p>In order for this to work, the accessor must be {@link #isMutable()
205+
* mutable}. See {@link MessageHeaderAccessor} for details.
206+
*/
202207
@Nullable
203208
public List<String> removeNativeHeader(String name) {
204209
Assert.state(isMutable(), "Already immutable");

spring-messaging/src/test/java/org/springframework/messaging/support/NativeMessageHeaderAccessorTests.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -112,8 +112,8 @@ public void createFromMessageAndModify() {
112112
(Map<String, List<String>>) actual.get(NativeMessageHeaderAccessor.NATIVE_HEADERS);
113113

114114
assertThat(actualNativeHeaders).isNotNull();
115-
assertThat(actualNativeHeaders.get("foo")).isEqualTo(Arrays.asList("BAR"));
116-
assertThat(actualNativeHeaders.get("bar")).isEqualTo(Arrays.asList("baz"));
115+
assertThat(actualNativeHeaders.get("foo")).isEqualTo(Collections.singletonList("BAR"));
116+
assertThat(actualNativeHeaders.get("bar")).isEqualTo(Collections.singletonList("baz"));
117117
}
118118

119119
@Test
@@ -124,7 +124,7 @@ public void setNativeHeader() {
124124
NativeMessageHeaderAccessor headers = new NativeMessageHeaderAccessor(nativeHeaders);
125125
headers.setNativeHeader("foo", "baz");
126126

127-
assertThat(headers.getNativeHeader("foo")).isEqualTo(Arrays.asList("baz"));
127+
assertThat(headers.getNativeHeader("foo")).isEqualTo(Collections.singletonList("baz"));
128128
}
129129

130130
@Test
@@ -143,7 +143,7 @@ public void setNativeHeaderLazyInit() {
143143
NativeMessageHeaderAccessor headerAccessor = new NativeMessageHeaderAccessor();
144144
headerAccessor.setNativeHeader("foo", "baz");
145145

146-
assertThat(headerAccessor.getNativeHeader("foo")).isEqualTo(Arrays.asList("baz"));
146+
assertThat(headerAccessor.getNativeHeader("foo")).isEqualTo(Collections.singletonList("baz"));
147147
}
148148

149149
@Test
@@ -161,9 +161,9 @@ public void setNativeHeaderImmutable() {
161161
headerAccessor.setNativeHeader("foo", "bar");
162162
headerAccessor.setImmutable();
163163

164-
assertThatIllegalStateException().isThrownBy(() ->
165-
headerAccessor.setNativeHeader("foo", "baz"))
166-
.withMessageContaining("Already immutable");
164+
assertThatIllegalStateException()
165+
.isThrownBy(() -> headerAccessor.setNativeHeader("foo", "baz"))
166+
.withMessageContaining("Already immutable");
167167
}
168168

169169
@Test
@@ -185,15 +185,15 @@ public void addNativeHeaderNullValue() {
185185
NativeMessageHeaderAccessor headers = new NativeMessageHeaderAccessor(nativeHeaders);
186186
headers.addNativeHeader("foo", null);
187187

188-
assertThat(headers.getNativeHeader("foo")).isEqualTo(Arrays.asList("bar"));
188+
assertThat(headers.getNativeHeader("foo")).isEqualTo(Collections.singletonList("bar"));
189189
}
190190

191191
@Test
192192
public void addNativeHeaderLazyInit() {
193193
NativeMessageHeaderAccessor headerAccessor = new NativeMessageHeaderAccessor();
194194
headerAccessor.addNativeHeader("foo", "bar");
195195

196-
assertThat(headerAccessor.getNativeHeader("foo")).isEqualTo(Arrays.asList("bar"));
196+
assertThat(headerAccessor.getNativeHeader("foo")).isEqualTo(Collections.singletonList("bar"));
197197
}
198198

199199
@Test
@@ -211,9 +211,9 @@ public void addNativeHeaderImmutable() {
211211
headerAccessor.addNativeHeader("foo", "bar");
212212
headerAccessor.setImmutable();
213213

214-
assertThatIllegalStateException().isThrownBy(() ->
215-
headerAccessor.addNativeHeader("foo", "baz"))
216-
.withMessageContaining("Already immutable");
214+
assertThatIllegalStateException()
215+
.isThrownBy(() -> headerAccessor.addNativeHeader("foo", "baz"))
216+
.withMessageContaining("Already immutable");
217217
}
218218

219219
@Test

0 commit comments

Comments
 (0)