I am trying to save incoming HttpHeaders inside a org.springframework.amqp.core.Message
to later pull out of the Message from a queue and cleanly
and use as HttpHeaders in a RestTemplate. It just doesn't seem very clean to me.
I have a @PostMapping in a spring rest controller which takes inbound HttpHeaders like this:
@PostMapping
public ResponseEntity<String> inbound(@PathVariable String flow, @RequestHeader HttpHeaders headers, @RequestBody byte[] payload) {
Which then calls createMessage
(below) method inside a org.springframework.amqp.core.Message
to store the HttpHeaders inside Message.
Retrieving the headers from the org.springframework.amqp.core.Message
like I am doing doesn't seem very clean because:
Map<String, Object> headers = message.getMessageProperties.getHeaders();
Does anyone know a cleaner way to pull the headers out of Message and add them to an HttpHeaders object? What I have seems rather assuming and clunky as I don't want to:
instanceof
and typecasting each datatype individually?import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.http.HttpHeaders;
import org.springframework.messaging.MessageHeaders;
import org.springframework.stereotype.Component;
@Component
public class MessageHelper {
public Message createMessage(HttpHeaders httpHeaders, byte[] payload) {
Map<String, Object> headers = new HashMap<>();
headers.putAll(httpHeaders);
return MessageBuilder
.withBody(payload)
.copyHeaders(new MessageHeaders(headers))
.setContentType(httpHeaders.getContentType().toString())
.setContentEncoding(StandardCharsets.UTF_8.displayName()).build();
}
public HttpHeaders getHeaders(Message message) {
HttpHeaders httpHeaders = new HttpHeaders();
Map<String, Object> headers = message.getMessageProperties().getHeaders();
for (Map.Entry<String, Object> header : headers.entrySet()) {
String value = header.getValue().toString().replace("]", "").replace("[", "");
httpHeaders.addIfAbsent(header.getKey(), value);
}
return httpHeaders;
}
}
Note: I am not using spring-integrations which seems to have other options like MessageHeaderAccessor
or spring-messaging which seems to have MessageHeaders
- but what could I be missing?
See here https://github.com/spring-projects/spring-amqp/blob/main/spring-rabbit/src/main/java/org/springframework/amqp/rabbit/support/DefaultMessagePropertiesConverter.java#L176-L223 for how Spring maps arbitrary headers when writing to AMQP.
If a header value is not one of the types that AMQP supports, a simple toString()
operation is performed on it (hence the [...]
, if it is something like a Set
).
Supported types:
boolean valid = (value instanceof String) || (value instanceof byte[])
|| (value instanceof Boolean) || (value instanceof Class)
|| (value instanceof LongString) || (value instanceof Integer) || (value instanceof Long)
|| (value instanceof Float) || (value instanceof Double) || (value instanceof BigDecimal)
|| (value instanceof Short) || (value instanceof Byte) || (value instanceof Date)
|| (value instanceof List) || (value instanceof Map) || (value instanceof Object[]);
For container types (arrays, lists) the method is called recursively.
One solution might be to serialize the headers into a single byte[]
header.