From 597c687da8888ef9c0cca774aeeefae615c6ffbe Mon Sep 17 00:00:00 2001 From: jbotuck Date: Thu, 25 Aug 2022 13:21:01 -0500 Subject: [PATCH 1/5] Fix indentation in ref docs for RestTemplate Closes gh-29014 --- src/docs/asciidoc/integration.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/docs/asciidoc/integration.adoc b/src/docs/asciidoc/integration.adoc index 91659a030b9d..70bb1333a3c7 100644 --- a/src/docs/asciidoc/integration.adoc +++ b/src/docs/asciidoc/integration.adoc @@ -306,7 +306,7 @@ to serialize only a subset of the object properties, as the following example sh ---- [[rest-template-multipart]] -===== Multipart +==== Multipart To send multipart data, you need to provide a `MultiValueMap` whose values may be an `Object` for part content, a `Resource` for a file part, or an `HttpEntity` for From cd10171f989b3ef0375a90efa01dfce059689a80 Mon Sep 17 00:00:00 2001 From: npriebe Date: Mon, 11 Jul 2022 15:20:13 +0200 Subject: [PATCH 2/5] Make WebSocketConnectionManager#isConnected public See gh-28785 --- .../web/socket/client/WebSocketConnectionManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java index 989100f93598..018267dcc768 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java @@ -160,7 +160,7 @@ protected void closeConnection() throws Exception { } @Override - protected boolean isConnected() { + public boolean isConnected() { return (this.webSocketSession != null && this.webSocketSession.isOpen()); } From 4eabe29b9af69d55e2b2d3aacfb7b0be9edf8e59 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 12 Sep 2022 10:52:53 +0100 Subject: [PATCH 3/5] Polishing contribution Closes gh-28785 --- .../client/ConnectionManagerSupport.java | 22 +++++++++---- .../client/WebSocketConnectionManager.java | 33 +++++++++---------- .../AnnotatedEndpointConnectionManager.java | 22 ++++++------- .../standard/EndpointConnectionManager.java | 21 ++++++------ 4 files changed, 51 insertions(+), 47 deletions(-) diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java index 03e816d58837..147938331c05 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/ConnectionManagerSupport.java @@ -25,11 +25,11 @@ import org.springframework.web.util.UriComponentsBuilder; /** - * A base class for WebSocket connection managers. Provides a declarative style of - * connecting to a WebSocket server given a URI to connect to. The connection occurs when - * the Spring ApplicationContext is refreshed, if the {@link #autoStartup} property is set - * to {@code true}, or if set to {@code false}, the {@link #start()} and #stop methods can - * be invoked manually. + * Base class for a connection manager that automates the process of connecting + * to a WebSocket server with the Spring ApplicationContext lifecycle. Connects + * to a WebSocket server on {@link #start()} and disconnects on {@link #stop()}. + * If {@link #setAutoStartup(boolean)} is set to {@code true} this will be done + * automatically when the Spring {@code ApplicationContext} is refreshed. * * @author Rossen Stoyanchev * @since 4.0 @@ -163,11 +163,19 @@ public boolean isRunning() { return this.running; } + /** + * Whether the connection is open/{@code true} or closed/{@code false}. + */ + public abstract boolean isConnected(); + /** + * Subclasses implement this to actually establish the connection. + */ protected abstract void openConnection(); + /** + * Subclasses implement this to close the connection. + */ protected abstract void closeConnection() throws Exception; - protected abstract boolean isConnected(); - } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java index 018267dcc768..a5c896021faf 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/WebSocketConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 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. @@ -29,10 +29,9 @@ import org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator; /** - * A WebSocket connection manager that is given a URI, a {@link WebSocketClient}, and a - * {@link WebSocketHandler}, connects to a WebSocket server through {@link #start()} and - * {@link #stop()} methods. If {@link #setAutoStartup(boolean)} is set to {@code true} - * this will be done automatically when the Spring ApplicationContext is refreshed. + * WebSocket {@link ConnectionManagerSupport connection manager} that connects + * to the server via {@link WebSocketClient} and handles the session with a + * {@link WebSocketHandler}. * * @author Rossen Stoyanchev * @since 4.0 @@ -46,7 +45,7 @@ public class WebSocketConnectionManager extends ConnectionManagerSupport { @Nullable private WebSocketSession webSocketSession; - private WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); + private final WebSocketHttpHeaders headers = new WebSocketHttpHeaders(); public WebSocketConnectionManager(WebSocketClient client, @@ -58,14 +57,6 @@ public WebSocketConnectionManager(WebSocketClient client, } - /** - * Decorate the WebSocketHandler provided to the class constructor. - *

By default {@link LoggingWebSocketHandlerDecorator} is added. - */ - protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) { - return new LoggingWebSocketHandlerDecorator(handler); - } - /** * Set the sub-protocols to use. If configured, specified sub-protocols will be * requested in the handshake through the {@code Sec-WebSocket-Protocol} header. The @@ -130,6 +121,11 @@ public void stopInternal() throws Exception { super.stopInternal(); } + @Override + public boolean isConnected() { + return (this.webSocketSession != null && this.webSocketSession.isOpen()); + } + @Override protected void openConnection() { if (logger.isInfoEnabled()) { @@ -159,9 +155,12 @@ protected void closeConnection() throws Exception { } } - @Override - public boolean isConnected() { - return (this.webSocketSession != null && this.webSocketSession.isOpen()); + /** + * Decorate the WebSocketHandler provided to the class constructor. + *

By default {@link LoggingWebSocketHandlerDecorator} is added. + */ + protected WebSocketHandler decorateWebSocketHandler(WebSocketHandler handler) { + return new LoggingWebSocketHandlerDecorator(handler); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java index fcb568e49040..993bdb3c4871 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/AnnotatedEndpointConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 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. @@ -31,11 +31,9 @@ import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; /** - * A WebSocket connection manager that is given a URI, a - * {@link javax.websocket.ClientEndpoint}-annotated endpoint, connects to a - * WebSocket server through the {@link #start()} and {@link #stop()} methods. - * If {@link #setAutoStartup(boolean)} is set to {@code true} this will be - * done automatically when the Spring ApplicationContext is refreshed. + * WebSocket {@link ConnectionManagerSupport connection manager} that connects + * to the server via {@link WebSocketContainer} and handles the session with an + * {@link javax.websocket.ClientEndpoint @ClientEndpoint} endpoint. * * @author Rossen Stoyanchev * @since 4.0 @@ -101,6 +99,12 @@ public TaskExecutor getTaskExecutor() { } + @Override + public boolean isConnected() { + Session session = this.session; + return (session != null && session.isOpen()); + } + @Override protected void openConnection() { this.taskExecutor.execute(() -> { @@ -135,10 +139,4 @@ protected void closeConnection() throws Exception { } } - @Override - protected boolean isConnected() { - Session session = this.session; - return (session != null && session.isOpen()); - } - } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java index 1fa1ed777c42..c2057ad0c82f 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/client/standard/EndpointConnectionManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2022 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. @@ -39,10 +39,9 @@ import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; /** - * A WebSocket connection manager that is given a URI, an {@link Endpoint}, connects to a - * WebSocket server through the {@link #start()} and {@link #stop()} methods. If - * {@link #setAutoStartup(boolean)} is set to {@code true} this will be done automatically - * when the Spring ApplicationContext is refreshed. + * WebSocket {@link ConnectionManagerSupport connection manager} that connects + * to the server via {@link WebSocketContainer} and handles the session with an + * {@link Endpoint}. * * @author Rossen Stoyanchev * @since 4.0 @@ -133,6 +132,12 @@ public TaskExecutor getTaskExecutor() { } + @Override + public boolean isConnected() { + Session session = this.session; + return (session != null && session.isOpen()); + } + @Override protected void openConnection() { this.taskExecutor.execute(() -> { @@ -168,10 +173,4 @@ protected void closeConnection() throws Exception { } } - @Override - protected boolean isConnected() { - Session session = this.session; - return (session != null && session.isOpen()); - } - } From d42f950a366d82aae3d72728853bdc1e0dbe71d2 Mon Sep 17 00:00:00 2001 From: Napster Date: Mon, 27 Jun 2022 20:50:48 +0200 Subject: [PATCH 4/5] Pass headers to STOMP receipt callbacks See gh-28715 --- .../simp/stomp/DefaultStompSession.java | 36 ++++++++++++------- .../messaging/simp/stomp/StompSession.java | 11 +++++- .../simp/stomp/DefaultStompSessionTests.java | 22 ++++++++++-- src/docs/asciidoc/web/websocket.adoc | 2 +- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java index 391325f443d7..e9ce9a1a17cc 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2022 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. @@ -27,6 +27,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import org.apache.commons.logging.Log; @@ -441,7 +442,7 @@ else if (logger.isDebugEnabled()) { String receiptId = headers.getReceiptId(); ReceiptHandler handler = this.receiptHandlers.get(receiptId); if (handler != null) { - handler.handleReceiptReceived(); + handler.handleReceiptReceived(headers); } else if (logger.isDebugEnabled()) { logger.debug("No matching receipt: " + accessor.getDetailedLogMessage(message.getPayload())); @@ -546,9 +547,9 @@ private class ReceiptHandler implements Receiptable { @Nullable private final String receiptId; - private final List receiptCallbacks = new ArrayList<>(2); + private final List> receiptCallbacks = new ArrayList<>(2); - private final List receiptLostCallbacks = new ArrayList<>(2); + private final List> receiptLostCallbacks = new ArrayList<>(2); @Nullable private ScheduledFuture future; @@ -556,6 +557,9 @@ private class ReceiptHandler implements Receiptable { @Nullable private Boolean result; + @Nullable + private StompHeaders receiptHeaders; + public ReceiptHandler(@Nullable String receiptId) { this.receiptId = receiptId; if (receiptId != null) { @@ -578,15 +582,20 @@ public String getReceiptId() { @Override public void addReceiptTask(Runnable task) { + addTask(h -> task.run(), true); + } + + @Override + public void addReceiptTask(Consumer task) { addTask(task, true); } @Override public void addReceiptLostTask(Runnable task) { - addTask(task, false); + addTask(h -> task.run(), false); } - private void addTask(Runnable task, boolean successTask) { + private void addTask(Consumer task, boolean successTask) { Assert.notNull(this.receiptId, "To track receipts, set autoReceiptEnabled=true or add 'receiptId' header"); synchronized (this) { @@ -604,10 +613,10 @@ private void addTask(Runnable task, boolean successTask) { } } - private void invoke(List callbacks) { - for (Runnable runnable : callbacks) { + private void invoke(List> callbacks) { + for (Consumer consumer : callbacks) { try { - runnable.run(); + consumer.accept(this.receiptHeaders); } catch (Throwable ex) { // ignore @@ -615,20 +624,21 @@ private void invoke(List callbacks) { } } - public void handleReceiptReceived() { - handleInternal(true); + public void handleReceiptReceived(StompHeaders receiptHeaders) { + handleInternal(true, receiptHeaders); } public void handleReceiptNotReceived() { - handleInternal(false); + handleInternal(false, null); } - private void handleInternal(boolean result) { + private void handleInternal(boolean result, @Nullable StompHeaders receiptHeaders) { synchronized (this) { if (this.result != null) { return; } this.result = result; + this.receiptHeaders = receiptHeaders; invoke(result ? this.receiptCallbacks : this.receiptLostCallbacks); DefaultStompSession.this.receiptHandlers.remove(this.receiptId); if (this.future != null) { diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java index 01ad81b8d444..9d1cebb391d7 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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,8 @@ package org.springframework.messaging.simp.stomp; +import java.util.function.Consumer; + import org.springframework.lang.Nullable; /** @@ -143,6 +145,13 @@ interface Receiptable { */ void addReceiptTask(Runnable runnable); + /** + * Consumer to invoke when a receipt is received. Accepts the headers of the received RECEIPT frame. + * @throws java.lang.IllegalArgumentException if the receiptId is {@code null} + * @since TBD + */ + void addReceiptTask(Consumer task); + /** * Task to invoke when a receipt is not received in the configured time. * @throws java.lang.IllegalArgumentException if the receiptId is {@code null} diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/stomp/DefaultStompSessionTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/stomp/DefaultStompSessionTests.java index 7f979b54213e..f4303835d10c 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/stomp/DefaultStompSessionTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/stomp/DefaultStompSessionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2022 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. @@ -576,22 +576,30 @@ public void receiptReceived() { this.session.setTaskScheduler(mock(TaskScheduler.class)); AtomicReference received = new AtomicReference<>(); + AtomicReference receivedHeaders = new AtomicReference<>(); StompHeaders headers = new StompHeaders(); headers.setDestination("/topic/foo"); headers.setReceipt("my-receipt"); Subscription subscription = this.session.subscribe(headers, mock(StompFrameHandler.class)); - subscription.addReceiptTask(() -> received.set(true)); + subscription.addReceiptTask(receiptHeaders -> { + received.set(true); + receivedHeaders.set(receiptHeaders); + }); assertThat((Object) received.get()).isNull(); StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.RECEIPT); accessor.setReceiptId("my-receipt"); + accessor.setNativeHeader("foo", "bar"); accessor.setLeaveMutable(true); this.session.handleMessage(MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders())); assertThat(received.get()).isNotNull(); assertThat(received.get()).isTrue(); + assertThat(receivedHeaders.get()).isNotNull(); + assertThat(receivedHeaders.get().get("foo").size()).isEqualTo(1); + assertThat(receivedHeaders.get().get("foo").get(0)).isEqualTo("bar"); } @Test @@ -600,6 +608,7 @@ public void receiptReceivedBeforeTaskAdded() { this.session.setTaskScheduler(mock(TaskScheduler.class)); AtomicReference received = new AtomicReference<>(); + AtomicReference receivedHeaders = new AtomicReference<>(); StompHeaders headers = new StompHeaders(); headers.setDestination("/topic/foo"); @@ -608,13 +617,20 @@ public void receiptReceivedBeforeTaskAdded() { StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.RECEIPT); accessor.setReceiptId("my-receipt"); + accessor.setNativeHeader("foo", "bar"); accessor.setLeaveMutable(true); this.session.handleMessage(MessageBuilder.createMessage(new byte[0], accessor.getMessageHeaders())); - subscription.addReceiptTask(() -> received.set(true)); + subscription.addReceiptTask(receiptHeaders -> { + received.set(true); + receivedHeaders.set(receiptHeaders); + }); assertThat(received.get()).isNotNull(); assertThat(received.get()).isTrue(); + assertThat(receivedHeaders.get()).isNotNull(); + assertThat(receivedHeaders.get().get("foo").size()).isEqualTo(1); + assertThat(receivedHeaders.get().get("foo").get(0)).isEqualTo("bar"); } @Test diff --git a/src/docs/asciidoc/web/websocket.adoc b/src/docs/asciidoc/web/websocket.adoc index b67b13d0d0c5..00f485b721f4 100644 --- a/src/docs/asciidoc/web/websocket.adoc +++ b/src/docs/asciidoc/web/websocket.adoc @@ -1347,7 +1347,7 @@ receipt if the server supports it (simple broker does not). For example, with th headers.setDestination("/topic/..."); headers.setReceipt("r1"); FrameHandler handler = ...; - stompSession.subscribe(headers, handler).addReceiptTask(() -> { + stompSession.subscribe(headers, handler).addReceiptTask(receiptHeaders -> { // Subscription ready... }); ---- From 4e9777696927fda00c2b428b91ba579a0775e19d Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 12 Sep 2022 11:47:55 +0100 Subject: [PATCH 5/5] Polishing contribution Closes gh-28715 --- .../simp/stomp/DefaultStompSession.java | 67 +++++++++++-------- .../messaging/simp/stomp/StompSession.java | 12 ++-- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java index e9ce9a1a17cc..5ab68ebf9eec 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/DefaultStompSession.java @@ -18,7 +18,6 @@ import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; @@ -549,7 +548,7 @@ private class ReceiptHandler implements Receiptable { private final List> receiptCallbacks = new ArrayList<>(2); - private final List> receiptLostCallbacks = new ArrayList<>(2); + private final List receiptLostCallbacks = new ArrayList<>(2); @Nullable private ScheduledFuture future; @@ -582,44 +581,34 @@ public String getReceiptId() { @Override public void addReceiptTask(Runnable task) { - addTask(h -> task.run(), true); + addReceiptTask(headers -> task.run()); } @Override public void addReceiptTask(Consumer task) { - addTask(task, true); - } - - @Override - public void addReceiptLostTask(Runnable task) { - addTask(h -> task.run(), false); - } - - private void addTask(Consumer task, boolean successTask) { - Assert.notNull(this.receiptId, - "To track receipts, set autoReceiptEnabled=true or add 'receiptId' header"); + Assert.notNull(this.receiptId, "Set autoReceiptEnabled to track receipts or add a 'receiptId' header"); synchronized (this) { - if (this.result != null && this.result == successTask) { - invoke(Collections.singletonList(task)); + if (this.result != null) { + if (this.result) { + task.accept(this.receiptHeaders); + } } else { - if (successTask) { - this.receiptCallbacks.add(task); - } - else { - this.receiptLostCallbacks.add(task); - } + this.receiptCallbacks.add(task); } } } - private void invoke(List> callbacks) { - for (Consumer consumer : callbacks) { - try { - consumer.accept(this.receiptHeaders); + @Override + public void addReceiptLostTask(Runnable task) { + synchronized (this) { + if (this.result != null) { + if (!this.result) { + task.run(); + } } - catch (Throwable ex) { - // ignore + else { + this.receiptLostCallbacks.add(task); } } } @@ -639,13 +628,33 @@ private void handleInternal(boolean result, @Nullable StompHeaders receiptHeader } this.result = result; this.receiptHeaders = receiptHeaders; - invoke(result ? this.receiptCallbacks : this.receiptLostCallbacks); + if (result) { + this.receiptCallbacks.forEach(consumer -> { + try { + consumer.accept(this.receiptHeaders); + } + catch (Throwable ex) { + // ignore + } + }); + } + else { + this.receiptLostCallbacks.forEach(task -> { + try { + task.run(); + } + catch (Throwable ex) { + // ignore + } + }); + } DefaultStompSession.this.receiptHandlers.remove(this.receiptId); if (this.future != null) { this.future.cancel(true); } } } + } diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java index 9d1cebb391d7..94875b6d0a97 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompSession.java @@ -141,23 +141,27 @@ interface Receiptable { /** * Task to invoke when a receipt is received. + * @param task the task to invoke * @throws java.lang.IllegalArgumentException if the receiptId is {@code null} */ - void addReceiptTask(Runnable runnable); + void addReceiptTask(Runnable task); /** - * Consumer to invoke when a receipt is received. Accepts the headers of the received RECEIPT frame. + * Variant of {@link #addReceiptTask(Runnable)} with a {@link Consumer} + * of the headers from the {@code RECEIPT} frame. + * @param task the consumer to invoke * @throws java.lang.IllegalArgumentException if the receiptId is {@code null} - * @since TBD + * @since 5.3.23 */ void addReceiptTask(Consumer task); /** * Task to invoke when a receipt is not received in the configured time. + * @param task the task to invoke * @throws java.lang.IllegalArgumentException if the receiptId is {@code null} * @see org.springframework.messaging.simp.stomp.StompClientSupport#setReceiptTimeLimit(long) */ - void addReceiptLostTask(Runnable runnable); + void addReceiptLostTask(Runnable task); }