GH-3785: Close stream for persistent collection (#3786)
* GH-3785: Close stream for persistent collection Fixes https://github.com/spring-projects/spring-integration/issues/3785 * Fix `CollectionArgumentResolver` and `PayloadsArgumentResolver` to close the `Stream` of message after its usage * Rework `AbstractKeyValueMessageStore.removeMessagesFromGroup()` to iterate input collection of messages not its stream to avoid the mentioned problem **Cherry-pick to `5.5.x`** * * Add `JdbcMessageStoreTests.testMessageGroupStreamNoConnectionPoolLeak()` to ensure that no leaks in the connection pool anymore. * Improve `MessageGroupStore.streamMessagesForGroup()` JavaDocs about requirements to close the `Stream` from persistent message store impls
This commit is contained in:
@@ -20,6 +20,7 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
@@ -71,17 +72,16 @@ public class CollectionArgumentResolver extends AbstractExpressionEvaluator
|
||||
if (this.canProcessMessageList) {
|
||||
Assert.state(value instanceof Collection,
|
||||
"This Argument Resolver only supports messages with a payload of Collection<Message<?>>, "
|
||||
+ "payload is: " + value.getClass());
|
||||
+ "payload is: " + value.getClass());
|
||||
|
||||
Collection<Message<?>> messages = (Collection<Message<?>>) value;
|
||||
|
||||
if (Message.class.isAssignableFrom(parameter.nested().getNestedParameterType())) {
|
||||
value = messages;
|
||||
}
|
||||
else {
|
||||
value = messages.stream()
|
||||
.map(Message::getPayload)
|
||||
.collect(Collectors.toList());
|
||||
if (!Message.class.isAssignableFrom(parameter.nested().getNestedParameterType())) {
|
||||
try (Stream<Message<?>> messageStream = messages.stream()) {
|
||||
value = messageStream
|
||||
.map(Message::getPayload)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
@@ -78,15 +79,17 @@ public class PayloadsArgumentResolver extends AbstractExpressionEvaluator
|
||||
return evaluateExpression(expression, messages, parameter.getParameterType());
|
||||
}
|
||||
else {
|
||||
List<?> payloads = messages.stream()
|
||||
.map(Message::getPayload)
|
||||
.collect(Collectors.toList());
|
||||
try (Stream<Message<?>> messageStream = messages.stream()) {
|
||||
List<?> payloads = messageStream
|
||||
.map(Message::getPayload)
|
||||
.collect(Collectors.toList());
|
||||
return getEvaluationContext()
|
||||
.getTypeConverter()
|
||||
.convertValue(payloads,
|
||||
TypeDescriptor.forObject(payloads),
|
||||
TypeDescriptor.valueOf(parameter.getParameterType()));
|
||||
}
|
||||
|
||||
return getEvaluationContext()
|
||||
.getTypeConverter()
|
||||
.convertValue(payloads,
|
||||
TypeDescriptor.forObject(payloads),
|
||||
TypeDescriptor.valueOf(parameter.getParameterType()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,17 +244,17 @@ public abstract class AbstractKeyValueMessageStore extends AbstractMessageGroupS
|
||||
Assert.isInstanceOf(MessageGroupMetadata.class, mgm);
|
||||
MessageGroupMetadata messageGroupMetadata = (MessageGroupMetadata) mgm;
|
||||
|
||||
List<UUID> ids =
|
||||
messages.stream()
|
||||
.map(messageToRemove -> messageToRemove.getHeaders().getId())
|
||||
.collect(Collectors.toList());
|
||||
List<UUID> ids = new ArrayList<>();
|
||||
for (Message<?> messageToRemove : messages) {
|
||||
ids.add(messageToRemove.getHeaders().getId());
|
||||
}
|
||||
|
||||
messageGroupMetadata.removeAll(ids);
|
||||
|
||||
List<Object> messageIds =
|
||||
ids.stream()
|
||||
.map(id -> this.messagePrefix + id)
|
||||
.collect(Collectors.toList());
|
||||
List<Object> messageIds = new ArrayList<>();
|
||||
for (UUID id : ids) {
|
||||
messageIds.add(this.messagePrefix + id);
|
||||
}
|
||||
|
||||
doRemoveAll(messageIds);
|
||||
|
||||
|
||||
@@ -156,6 +156,9 @@ public interface MessageGroupStore extends BasicMessageGroupStore {
|
||||
|
||||
/**
|
||||
* Return a stream for messages stored in the provided group.
|
||||
* The persistent implementations return a Stream which has
|
||||
* to be closed once fully processed (e.g. through a try-with-resources clause).
|
||||
* By default, it streams a result of {@link #getMessagesForGroup(Object)}.
|
||||
* @param groupId the group id to retrieve messages.
|
||||
* @return the {@link Stream} for messages in this group.
|
||||
* @since 5.5
|
||||
|
||||
Reference in New Issue
Block a user