This commit makes the 3 existing InvocableHandlerMethod types more
consistent and comparable with each other.
1. Use of consistent method names and method order.
2. Consistent error formatting.
3. Explicit for loops for resolving argument values in webflux variant
because that makes it more readable, creates less garabage, and it's
the only way to bring consistency since the other two variants cannot
throw exceptions inside Optional lambdas (vs webflux variant which can
wrap it in a Mono).
4. Use package private HandlerMethodArgumentComposite in webflux
variant in order to pick up the resolver argument caching that the
other two variants have.
5. Polish tests.
6. Add missing tests for messaging variant.
Tomcat and Jetty integration tests were moved out of spring-messaging
a very long time ago (before 4.0), but the dependencies remained
unnoticed until now.
This was a package private class in spring-messaging since 5.0, and was
recently made public in 5.1. This commit promotes it to spring-core
where it belongs next to all other ListenableFuture support classes.
Follow-up refactoring for SPR-17336
Collapse the package private AbstractMonoToListenableFutureAdapter into
its only sub-class MonoToListenableFutureAdapter. There is no need for
such an abstract class that makes it possible to adapt from one source
to a different target type. That's already covered by
ListenableFutureAdapter.
Follow-up refactoring for SPR-17336.
Empty Maps are preferably initialized without capacity (not initializing them at all or lazily initializing with default capacity when needed).
Issue: SPR-17105
This commit adds support for single-value reactive types in
@MessageMapping by converting them using ReactiveAdapterRegistry
and MonoToListenableFutureAdapter.
MonoToListenableFutureAdapter previously package private and used only
in org.springframework.messaging.tcp.reactor has been moved to
org.springframework.messaging.support and made public in order to be
used by ReactiveReturnValueHandler as well.
Issue: SPR-16634
Update all classes so that inner classes are always last. Also
ensure that utility classes are always final and have a private
constructor and make exceptions final whenever possible.
Issue: SPR-16968
Prior to this commit, the generated POMs for Spring Framework modules
would contain unneeded/harmful information from the Spring Framework
build:
1. The BOM imports applied to each module by the dependency
management plugin, for example for Netty or Reactor Netty.
Spring should not export that opinion to its POMs.
2. The exclusion of "org.slf4:jcl-over-slf4j" from *all* dependencies,
which made the POMs much larger than necessary and suggested to
developers that they should exclude it as well when using all those
listed dependencies. In fact, only Apache Tiles currently brings that
transitively.
This commit removes that information from the POMs.
The dependencyManagement Gradle plugin is disabled for POM generation
and we manually resolve the dependency versions during the generation
phase.
The Gradle build is streamlined to exclude "org.slf4:jcl-over-slf4j"
only when necessary.
Issue: SPR-16893
After the recent changes to expose configuring TcpOperations, it no
longer makes sense to automatically log the relayHost/Port since that's
mutually exclusive with a custom TcpOperations.
Instead we delegate to TcpOperations.toString().
Issue: SPR-16801
HandlerMethodReturnValueHandlerComposite and
AbstractMethodMessageHandler iterate using index over collections
implementing RandomAccess to avoid unnecessary iterators.
Rather than create a new EvaluationContext instance per evaluation, we
now create a statically shared instance, without the root object in it,
and re-use it for all evalutations.
As of 4.3.13 MappingJackson2MessageConverter uses the MethodParameter
hint to obtain generic type information but it needs to be careful, and
nest one level, if the target parameter type has a Message wrapper.
Issue: SPR-16486
After this commit DefaultUserDestinationResolves no longer looks at
whether AntPathMatcher is configured with "." as separator and rather
expects to be explicitly told whether to keep the leading slash in
translated destinations which actually depends on what the message
broker supports (e.g. RabbitMQ "/", Artemis ".") or how it is
configured (simple broker could be either way).
There is also a minor improvement in SimpMessagingTemplate to ensure
user destinations are correctly formed based on what the
DefaultUserDestinationResolver expects. When using "." as separtor it
allows sending messages to "queue.q1" rather than "/queue.q1".
Issue: SPR-16275
SimpMessageTypeMessageCondition was lenient in matching the message
type, essentially matching on any non-null message type with an exact
match given a preference only in comparing mulitple matches.
This commit modifies matching logic to look for an exact match.
Issue: SPR-16109
Also, ChannelRegistration.setInterceptors is deprecated now: in favor of a fluently named interceptors(...) method which is documented to add the given interceptors to the channel's current list.
Issue: SPR-15962
Issue: SPR-15976
This commit introduces the following changes.
1) It adds a new Spring @NonNull annotation which allows to apply
@NonNullApi semantic on a specific element, like @Nullable does.
Combined with @Nullable, it allows partial null-safety support when
package granularity is too broad.
2) @Nullable and @NonNull can apply to ElementType.TYPE_USE in order
to be used on generic type arguments (SPR-15942).
3) Annotations does not apply to ElementType.TYPE_PARAMETER anymore
since it is not supported yet (applicability for such use case is
controversial and need to be discussed).
4) @NonNullApi does not apply to ElementType.FIELD anymore since in a
lot of use cases (private, protected) it is not part for the public API
+ its usage should remain opt-in. A dedicated @NonNullFields annotation
has been added in order to set fields default to non-nullable.
5) Updated Javadoc and reference documentation.
Issue: SPR-15756
This commit applies the Dependency Management Plugin to modules that
require it; right now Spring Framework is importing BOMs for Netty and
Reactor dependencies only.
Instead of applying those BOMs to all modules, they're applied only
where they're needed.
Issue: SPR-15885
The main `build.gradle` file contains now only the common build
infrastructure; all module-specific build configurations have
been moved to their own build file.
Issue: SPR-15885
Includes general streamlining of dependency declarations with reduced version variables, direct use of EclipseLink 2.7 and its implicit JPA 2.2 dependency in spring-orm, mixed use of Hibernate 5.2.10 and 5.1.10 for integration tests, as well as an upgrade to Jetty 9.4.7 RC0 and a downgrade to Groovy 2.4.12 (since Groovy 2.5 won't be final in time for Spring Framework 5.0).
Issue: SPR-15879
Issue: SPR-15880
Bean-derived null values may still get passed into bean properties and injection points but only if those are declared as non-required. Note that getBean will never return null; a manual bean.equals(null) / "null".equals(bean.toString()) check identifies expected null values now. This will only ever happen with custom FactoryBeans or factory methods returning null - and since all common cases are handled by autowiring or bean property values in bean definitions, there should be no need to ever manually check for such a null value received from getBean.
Issue: SPR-15829
This commit ensure that null-safety is consistent between
getters and setters in order to be able to provide beans
with properties with a common type when type safety is
taken in account like with Kotlin.
It also add a few missing property level @Nullable
annotations.
Issue: SPR-15792
This commits extends nullability declarations to the field level, formalizing the interaction between methods and their underlying fields and therefore avoiding any nullability mismatch.
Issue: SPR-15720
This commit also removes nullability from two common spots: ResolvableType.getType() and TargetSource.getTarget(), both of which are never effectively null with any regular implementation. For such scenarios, a non-null empty type/target is the cleaner contract.
Issue: SPR-15540
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments.
Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit.
Issue: SPR-15540
The change to "optimize" the template by not rebuilding the reply
message when the original header channels was null was incorrect.
We need to null out those headers if they were originally null.
Issue: SPR-15991
Provide a mechanism to override the configured send and receive
timeouts in the GenericMessagingTemplate.
- overload `doReceive()` to take a receive timeout argument
- for `sendAndReceive()` methods examine message headers for these
timeout values
- remove headers to avoid propagation
- avoid the unconditional rebuild of the reply message if the
original headers weren't present
- also remove headers from simple `send()` operations
- change javadocs for the setters to indicate they are now defaults
- add properties to allow the user to override the header names used
- change `TemporaryReplyChannel` to use `send` arg and change to static
- add package-protected ctor to avoid the compiler creating a
synthetic constructor for access
Issue: SPR-15591
This commit introduces 2 new @Nullable and @NonNullApi
annotations that leverage JSR 305 (dormant but available via
Findbugs jsr305 dependency and already used by libraries
like OkHttp) meta-annotations to specify explicitly
null-safety of Spring Framework parameters and return values.
In order to avoid adding too much annotations, the
default is set at package level with @NonNullApi and
@Nullable annotations are added when needed at parameter or
return value level. These annotations are intended to be used
on Spring Framework itself but also by other Spring projects.
@Nullable annotations have been introduced based on Javadoc
and search of patterns like "return null;". It is expected that
nullability of Spring Framework API will be polished with
complementary commits.
In practice, this will make the whole Spring Framework API
null-safe for Kotlin projects (when KT-10942 will be fixed)
since Kotlin will be able to leverage these annotations to
know if a parameter or a return value is nullable or not. But
this is also useful for Java developers as well since IntelliJ
IDEA, for example, also understands these annotations to
generate warnings when unsafe nullable usages are detected.
Issue: SPR-15540
Currently the BOM versions are:
* reactor-core 3.0.6.BUILD-SNAPSHOT
* reactor-netty 0.6.2.BUILD-SNAPSHOT
This commit fixes as well a few deprecations in reactor-core.
This commit *adds* the "intercepted" headers to the ClientHttpRequest,
as opposed to replacing them, which is what happened before this commit.
Issue: SPR-15166
When connecting with a ReconnectStrategy we can only report the outcome
of the first connect to the ListenableFuture<Void> return value.
Failures for all subsequent attempts to reconnect however must be
channeled to TcpConnectHandler#afterConnectFailure which is used in
the STOMP broker relay for example to publish
BroadcastAvailability(true/false) events.
When decoding STOMP messages unread portions of a given input ByteBuf
must be kept until more input is received and the next complete STOMP
frame can be parsed.
In Reactor Net 2.x this was handled for us through the "remainder"
field in NettyChannelHandlerBridge. The Reactor Netty 0.6 upgrade
however applied only a simple map operator on the input ByteBuf
after which the buffer is relased.
This commit replaces the use of a simple map operator for decoding
and installs a ByteToMessageDecoder in the Netty channel pipeline
which has a built-in ability to preserve and merge unread input into
subsequent input buffers.
Create a ReactorNettyCodec to hold the decoding and encoding function
and consumer along with a package-private sub-class that delegates to
StompDecoder and StompEncoder.
Issue: SPR-14531
This commit polishes Kotlin nullable support by reusing
MethodParameter#isOptional() instead of adding a new
MethodParameter#isNullable() method, adds
Kotlin tests and introduces Spring Web Reactive
support.
Issue: SPR-14165
Where `isOptional` is used, also check for `isNullable` i.e.
values are not considered required if they are Kotlin nullables:
- spring-messaging: named value method arguments
- spring-web: named value method arguments
- spring-webmvc: request parts
This means that Kotlin client code no longer has to explicity specify
"required=false" for Kotlin nullables -- this information is inferred
automatically by the framework.
Issue: SPR-14165
Resetting the connection first before invoking a failure callback on
the application handler ensures that any checks to isConnected will
return false.
Issue: SPR-14721
xmlunit 2.1.0 is the latest release for xmlunit.
Most of the xmlunit functionality used within spring-framework
was done through the xmlunit 1.x helper class
`org.custommonkey.xmlunit.XMLAssert`.
As of xmlunit 2.0.0 most of the XML comparison methods are done
through hamcrest matchers exposed by the xmlunit-matchers
library. In some cases during the migration, the matchers
had to be customized with custom `NodeMatcher` or
`DifferenceEvaluator` instances in order to keep the assertions
correct (they were performed with xmlunit 1.x previously).
Issue: SPR-14043
This commit adds a test runtime dependency on log4j 2 for every project
and migrates all log4j.properties files to log4j2-test.xml files.
Issue: SPR-14431
Normally heartbeats keep connections from hanging. However in some
cases a connection may hang before a CONNECTED frame is received
and heartbeats are put in place. This commit adds a change to enforce
a 60 limit on receiving the CONNECTED frame.
Issue: SPR-14266
SendTo and SendToUser are treated as mutually exclusive. The addition of
type-level support in 4.3. RC1 however did not consider the possibility
to mix and match of the two betwee type and method level.
This commit consolidates the detection of SendTo and SendToUser
annotations and considers them all together.
Issue: SPR-14238
Before this commit the DefaultUserDestinationResolver did not support
well broker destinations that use dot as separator with a built in
assumptions that the destinations it resolves must start with slash.
This change adds PathMatcher property that is used to determine if
an alternative path separator is in use and if so the leading slash is
left out.
Issue: SPR-14044
The MultiServerUserRegistry now supports scenarios where the same user
is connected to multiple servers. For such cases the SimpUser returned
from the registry exposes all sessions across all servers.
Issue: SPR-13800
The MessageMethodArgumentResolver now also supports applying a
MessageConverter to the payload.
This is effectively a shortcut for declaring a method with an @Payload
argument + MessageHeaders and then creating a new message from the two.
Issue: SPR-13288
This change updates all cases where callbacks are invoked to catch and
suppress errors (since there is not match to do with and error from
a callback be it success or failure).
Also updated is the contract itself to clarify this and emphasize the
callbacks are really notifications for the outcome of the
ListenableFuture not the callbacks themselves.
Issue: SPR-13785
When the cacheLimit is reached and there is an eviction from the
updateCache, the accessCache is now also updated.
This change also ensures that adding a destination to the cache is
protected with synchronization on the updateCache.
Issue: SPR-13555
We can't compile directly against NettyClientSocketOptions method which
changed signatures in 2.0.6. This change ensures the method is invoked
reflectively instead.
SPR-11512 introduced support for annotation attribute aliases via
@AliasFor, requiring the explicit declaration of the 'attribute'
attribute. However, for aliases within an annotation, this explicit
declaration is unnecessary.
This commit improves the readability of alias pairs declared within an
annotation by introducing a 'value' attribute in @AliasFor that is an
alias for the existing 'attribute' attribute. This allows annotations
such as @ContextConfiguration from the spring-test module to declare
aliases as follows.
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
Issue: SPR-13289
AbstractMessageConverter provides overloaded methods with a conversion hint, MappingJackson2MessageConverter takes that hint into account, and SimpMessagingTemplate transformes such a hint in the given headers map into an explicit argument invocation argument.
Issue: SPR-13265
After SPR-12884 (4.2 RC1) introduced support for a selector header
expression on SUBSCRIBE frames, messages from the destination cache
are further filtered based on the selector expression. While adding a
test to find subscriptions at the same time as unsubscribing, a
potential NPE was exposed. This commit fixes the NPE.
Issue: SPR-13204
This split avoids a package tangle (between core and core.annotation) and also allows for selective use of raw annotation exposure versus synthesized annotations, with the latter primarily applicable to web and message handler processing at this point.
Issue: SPR-13153
This commit introduces support for asynchronous return values thanks
to the new AsyncHandlerMethodReturnValueHandler interface. Out of
the box support for ListenableFuture is also provided.
Issue: SPR-12168
This change introduces SimpUserRegistry exposing an API to access
information about connected users, their sessions, and subscriptions
with STOMP/WebSocket messaging. Provides are methods to access users
as well as a method to find subscriptions given a Matcher strategy.
The DefaultSimpUserRegistry implementation is also a
SmartApplicationListener which listesn for ApplicationContext events
when users connect, disconnect, subscribe, and unsubscribe to
destinations.
The MultiServerUserRegistry implementation is a composite that
aggregates user information from the local SimpUserRegistry as well
as snapshots of user on remote application servers.
UserRegistryMessageHandler is used with MultiServerUserRegistry. It
broadcats user registry information through the broker and listens
for similar broadcasts from other servers. This must be enabled
explicitly when configuring the STOMP broker relay.
The existing UserSessionRegistry which was primiarly used internally
to resolve a user name to session id's has been deprecated and is no
longer used. If an application configures a custom UserSessionRegistr
still, it will be adapted accordingly to SimpUserRegistry but the
effect is rather limited (comparable to pre-existing functionality)
and will not work in multi-server scenarios.
Issue: SPR-12029
This commit introduces a messaging.converter.MessageConverter that
marshals to/from XML using the abstractions provided in the OXM module.
Issue: SPR-12726
This change adds support for broadcasting messages with unresolved
user destinations so that other servers can try to resolve it.
That enables sending messages to users who may be connected to a
different server.
Issue: SPR-11620
Revised HandlerMethod.getBeanType() impl for both web and messaging.
In addition, HandlerMethods get created with the internal BeanFactory now.
Issue: SPR-12832
This change adds support for global @MessageExceptionHandler methods
with STOMP over WebSocket messages. Such methods can be added to
@ControllerAdvice annotated components, much like @ExceptionHandler
methods for Spring MVC.
Issue: SPR-12696
WebSocketStompClient can be used with any implementation of
org.springframework.web.socket.client.WebSocketClient, which includes
org.springframework.web.socket.sockjs.client.SockJsClient.
Reactor11TcpStompClient can be used with reactor-net and provides STOMP
over TCP. It's also possible to adapt other WebSocket and TCP client
libraries (see StompClientSupport for more details).
For example usage see WebSocketStompClientIntegrationTests.
Issue: SPR-11588
Add support for annotation-based event listeners. Enabled automatically
when using Java configuration or can be enabled explicitly via the
regular <context:annotation-driven/> XML element. Detect methods of
managed beans annotated with @EventListener, either directly or through
a meta-annotation.
Annotated methods must define the event type they listen to as a single
parameter argument. Events are automatically filtered out according to
the method signature. When additional runtime filtering is required, one
can specify the `condition` attribute of the annotation that defines a
SpEL expression that should match to actually invoke the method for a
particular event. The root context exposes the actual `event`
(`#root.event`) and method arguments (`#root.args`). Individual method
arguments are also exposed via either the `a` or `p` alias (`#a0` refers
to the first method argument). Finally, methods arguments are exposed via
their names if that information can be discovered.
Events can be either an ApplicationEvent or any arbitrary payload. Such
payload is wrapped automatically in a PayloadApplicationEvent and managed
explicitly internally. As a result, users can now publish and listen
for arbitrary objects.
If an annotated method has a return value, an non null result is actually
published as a new event, something like:
@EventListener
public FooEvent handle(BarEvent event) { ... }
Events can be handled in an aynchronous manner by adding `@Async` to the
event method declaration and enabling such infrastructure. Events can
also be ordered by adding an `@Order` annotation to the event method.
Issue: SPR-11622
Prior to this change when adding subscriptions
DefaultSubscriptionRegistry (incorrectly) made a copy of the given map
for its "access" cache rather than for its "update" cache.
Issue: SPR-12665
This change removes the need for the isStreaming field from the base
class AbstractHttpSockJsSession. This field was used to account for
differences between polling vs streaming SockJS sessions without having
to expose to sub-classes private fields that are otherwise protected
from concurrent access by the base class. The change manages to delegate
to sub-classes without providing direct access to protected fields.
Issue: SPR-12427
The test was verifying that when a DISCONNECT frame is sent to the
broker, there will be no further messages on the clientOutboundChannel.
This is generally true, however in some cases when the broker receives
a DISCONNECT it may close its connection fast enough (before we do) in
which case we send an ERROR message downstream to ensure the WebSocket
side is cleaned up. Either way the downstream should be idempotent
with regards to cleaning up sessions.
With this commit, Jackson builder is now used in spring-websocket
to create the ObjectMapper instance.
It is not possible to use the builder for spring-messaging
and spring-jms since these modules don't have a dependency on
spring-web, thus they now just customize the same features:
- MapperFeature#DEFAULT_VIEW_INCLUSION is disabled
- DeserializationFeature#FAIL_ON_UNKNOWN_PROPERTIES is disabled
Issue: SPR-12293
This commit fixes the parsing of message destinations such as
"/user/anna/queue/foo", reverting a regression introduced by SPR-11506,
which worked well with @SendToUser use cases but caused issues for
messages sent to other users.
Issue: SPR-12444
Before this change the simple broker simply removed subscriptions
upon receiving a DISCONNECT message assuming it was a result of
a client STOMP WebSocket session ending.
However, if the server-side application sends a DISCONNECT to
the broker in order to terminate a session, the STOMP WebSocket
session could remain unware without any further action. This
change ensures the simple broker sends a DISCONNECT_ACK message
downstream whenever it receives a DISCONNECT.
Issue: SPR-12288
This change adds a ChannelInterceptor that flips the immutable flag on
messages being sent. This allows components sending messages to leave
the message mutable for interceptors to further apply modifications
before the message is sent (and exposed to concurrency).
The interceptor is automatically added with the STOMP/WebSocket Java
and XML config and the StompSubProtocolHandler leaves parsed incoming
messages mutable so they can be further modified before being sent.
Issue: SPR-12321
The new contract allows registration of interceptors with any
MessageChannel implementation hierarchy -- for example the one in the
Spring Framework or the one in Spring Integration.
When a DISCONNECT is sent to the broker, we proactively close the TCP
connection unless the DISCONNECT has a receipt header. Depending on
the timing, the broker may also close the connection on its side.
That appears to cause an exception in reactor on the CI server, e.g.:
https://build.spring.io/browse/SPR-PUB-JOB1-1715/test/case/135247530
This change traps the exceptions and prevents it from propagating.
This change uses a ChannelInterceptor (inserted at index 0) to detect
when a DISCONNECT message is precluded from being sent on the
clientInboundChannel. This can happen if another interceptor allows
a runtime exception out from preSend or returns false.
It is crucial for such messages to be processed, so when detected
they're processed still.
Issue: SPR-12218
This commit also turns MessagingException into a NestedRuntimeException subclass which delivers a root message that has the cause message appended to it. That's a common expectation with the use of Spring exceptions since all of our exception hierarchies have historically been designed that way.
Issue: SPR-12064
Issue: SPR-12038
This commit moves JmsHandlerMethodFactory and its default
implementation to the messaging abstraction. Working on a similar
support for AMQP revealed that this factory has nothing that is JMS
specific and is exactly identical in the case of AMQP.
Issue: SPR-12053
This commit introduces MessagingExceptionTranslator, a messaging
exception translation infrastructure similar to what
PersistenceExceptionTranslator provides.
JmsMessagingTemplate does not throw raw JmsException anymore but
translates those to an instance of Spring's MessagingException
hierarchy.
Issue: SPR-12038
This commit updates JmsMessagingTemplate to support the
MessageRequestReplyOperation interface that provides synchronous
request/reply operations.
As JmsMessagingTemplate delegates everything under the scenes to
JmsTemplate, the latter has been updated as well to offer such lower
level operation.
Issue: SPR-12037
Make it possible to use a ListenableFuture with Java 8
lambda expressions, using a syntax like
listenableFuture.addCallback(() -> ..., () -> ...);
Issue: SPR-11820
In order to be able to use separators like "." (used by default
by most broker relays) instead of "/" for destination patterns
handling, the PathMatcher used in spring-messaging can now
be customized easily thanks to XML websocket namespace
or JavaConfig.
AntPathMatcher has been updated in order to use the configured path
separator instead of an hardcoded "/" for path concatenation.
Extension handling is now disabled when the "." separator is configured.
Issue: SPR-11660
This change removes most logging at INFO level and also ensures the
amount of information logged at DEBUG level is useful, brief, and
not duplicated.
Also added is custom logging for STOMP frames to ensure very readable
and consise output.
Issue: SPR-11934
This change adds collection of stats in key infrastructure components
of the WebSocket message broker config setup and exposes the gathered
information for logging and viewing (e.g. via JMX).
WebSocketMessageBrokerStats is a single class that assembles all
gathered information and by default logs it once every 15 minutes.
Application can also easily expose to JMX through an MBeanExporter.
A new section in the reference documentation provides a summary of
the available information.
Issue: SPR-11739
Avoid using destination pattern based search when removing sessions or
subscriptions from DefaultSubscriptionRegistry and use only session and
subscription ids.
Issue: SPR-11930
Update WebSocketSession toString methods to include the handshake URI
and add id and URI fields to ensure they're available after close().
Log WebSocket session open and close events at INFO.
Remove trace messages for destinations that do not match.
Issue: SPR-11884
Optimize logging with tracking the opening and closing of WebSocket
sessions and STOMP broker connections in mind.
While the volume of messages makes it impractical to log every message
at anything higher than TRACE, the opening and closing of connections
is more manageable and can be logged at INFO. This makes it possible to
drop to INFO in production and get useful information without getting
too much in a short period of time.
The logging is also optimized to avoid providing the same information
from multiple places since messages pass through multiple layers.
Issue: SPR-11884
Prior to this commit, no exception was raised if a message could not
be converted to the requested payload because no suitable converter
were found.
This commit adds an explicit check if the converted payload is null.
Issue: SPR-11817
This commit revisits JmsMessagingTemplate and adds support for
receiving operations as well. JmsMessageSendingOperations has been
renamed to JmsMessageOperations.
The messaging abstraction did not split receiving and request-reply
operations. AbstractMessageReceivingTemplate has been created to hold
only the receiving operations.
Issue: SPR-11772
This commit adds a JMS implementation of MessageSendingOperations,
allowing to send JMS messages using Spring's standard Messaging
abstraction.
MessagingMessageConverter is a standard JMS's MessageConverter that
can convert Spring's Message to JMS message and vice versa. Existing
infrastructure has been updated to use this implementation.
Issue: SPR-11772
This change adds support for a custom "websocket" scope.
WebSocket-scoped beans may be injected into controllers with message
handling methods as well as channel interceptor registered on the
"inboundClientChannel".
Issue: SPR-11305
Before this change, subscribing to a user destination and use of
@SendToUser annotation required an authenticated user.
This change makes it possible to subscribe to a user destination from
WebSocket sessions without an authenticated user. In such cases the
destination is associated with one session only rather than with a
user (and all their sessions).
It is then also possible to send a message to a user destination
via "/user/{sessionId}/.." rather than "/user/{user}/...".
That means @SendToUser works relying on the session id of the input
message, effectively sending a reply to destination private to the
session.
A key use case for this is handling an exception with an
@MessageExceptionHandler method and sending a reply with @SendToUser.
Issue: SPR-11309
Removal of cached destination is now moved outside the for loop
that removes subscriptions to avoid ConcurrentModificationException.
Also since updateCache is a LinkedHashMap with accessOrder=true,
a simple access with updateCache.get() modify the map.
By iterating over updateCache.entrySet(), we avoid this update.
Issue: SPR-11755
Added the ability to send a message only to one user session. Given a
user has two tabs open and the client sends a message to the server
from tab 1, it is now possible to send a reply message to only 1 tab
instead of the default mode of targetting all known user sessions.
Issue: SPR-11506
DestinationCache is now used for both plain and pattern
destinations. It stores internally the subscriptions map for each
cached destination. Subscriptions are initially created when there
is no cache for the requested destination, and are updated when
subscriptions change.
Issue: SPR-11657
This change simplifies the implementation of the "test" EventPublisher
and MessageHandler used in the STOMP broker relay integration tests.
The updated implementations use a time-limted poll on a BlockingQueue.
The original fix for SPR-11423:
32e5f57e64
was insufficient when using an external broker since the original
destination header has to be in the "native headers" map (i.e. with
STOMP headers) in order to be included in messages broadcast by
the broker.
This commit replaces the "responseDestination" attribute on the
JmsListener annotation by a support of the standard SendTo annotation.
Issue: SPR-11707
This change modifies the names of the Reactor support classes in order
to align with the same changes in the 4.0.x line which now supports
both Reactor 1.1 and 1.0.
Issue: SPR-11636
This commit adds the support of JMS annotated endpoint. Can be
activated both by @EnableJms or <jms:annotation-driven/> and
detects methods of managed beans annotated with @JmsListener,
either directly or through a meta-annotation.
Containers are created and managed under the cover by a registry
at application startup time. Container creation is delegated to a
JmsListenerContainerFactory that is identified by the containerFactory
attribute of the JmsListener annotation. Containers can be
retrieved from the registry using a custom id that can be specified
directly on the annotation.
A "factory-id" attribute is available on the container element of
the XML namespace. When it is present, the configuration defined at
the namespace level is used to build a JmsListenerContainerFactory
that is exposed with the value of the "factory-id" attribute. This can
be used as a smooth migration path for users having listener containers
defined at the namespace level. It is also possible to migrate all
listeners to annotated endpoints and yet keep the
<jms:listener-container> or <jms:jca-listener-container> element to
share the container configuration.
The configuration can be fine-tuned by implementing the
JmsListenerConfigurer interface which gives access to the registrar
used to register endpoints. This includes a programmatic registration
of endpoints in complement to the declarative approach. A default
JmsListenerContainerFactory can also be specified to be used if no
containerFactory has been set on the annotation.
Annotated methods can have flexible method arguments that are similar
to what @MessageMapping provides. In particular, jms listener endpoint
methods can fully use the messaging abstraction, including convenient
header accessors. It is also possible to inject the raw
javax.jms.Message and the Session for more advanced use cases. The
payload can be injected as long as the conversion service is able to
convert it from the original type of the JMS payload. By
default, a DefaultJmsHandlerMethodFactory is used but it can be
configured further to support additional method arguments or to
customize conversion and validation support.
The return type of an annotated method can also be an instance of
Spring's Message abstraction. Instead of just converting the payload,
such response type allows to communicate standard and custom headers.
The JmsHeaderMapper infrastructure from Spring integration has also
been migrated to the Spring framework. SimpleJmsHeaderMapper is based
on SI's DefaultJmsHeaderMapper. The simple implementation maps all
JMS headers so that the generated Message abstraction has all the
information stored in the protocol specific message.
Issue: SPR-9882
An initial commit with expanded support for static resource handling:
- Add ResourceResolver strategy for resolving a request to a Resource
along with a few implementations.
- Add PublicResourceUrlProvider to get URLs for client-side use.
- Add ResourceUrlEncodingFilter and
PublicResourceUrlProviderExposingInterceptor along with initial
MVC Java config support.
Issue: SPR-10933
Introduce MessageHeaderInitializer strategy for initializing a
MessageHeaderAccessor.
Add IdTimestampMessageHeaderInitializer implementation that provides
control over ID and timestamp header generation.
Disable ID and timestamp by default in SimpMessageHeaderAccessor and
therefore its sub-class StompHeaderAccessor.
Issue: SPR-11468
The BufferingStompDecoder now decorates rather than extend
StompDecoder. This allows a single StompDecoder instance to be
configured and extended independantly while buffering remains a
separate concern.
AbstractMessageConverter and messaging template implementations now
detect and use mutable headers if passed in.
The SimpMessagingTemplate is optimized to supporting using a single
MessageHeaders instance while preparing a message.
This commit also updates code using the SimpMessagingTemplate to take
advantage of its new capabilities.
Issue: SPR-11468
Mutate rather than re-create headers when decoding STOMP messages
before a message is sent on a message channel.
Use MessageBuilder.createMessage to ensure the fully prepared
MessageHeaders is used directly MessageHeaderAccessor instance.
Issue: SPR-11468
Refine semantics of ID and TIMESTAMP headers provided to protected
MessageHeaders constructor.
Refactor internal implementation of MessageHeaderAccessor.
Support mutating headers from a single thread while a message is being
built (e.g. StompDecoder creating message + then adding session id).
Improve immutablity in NativeMessageHeaderAccessor and in
StompHeaderAccessor.
Optimize object creation for initializing messages and subsequent
accessing their headers.
Introduce MessageHeaderAccessorFactory support to enable applying a
common strategies for ID and TIMESTAMP generation to every message.
Add MessageBuilder shortcut factory method for creating messages from
payload and a full-prepared MessageHeaders instance. Also add
equivalent constructors to GenericMessage and ErrorMessage.
Issue: SPR-11468
The UserDestinationMessageHandler adds a header providing a hint for
what the original destination a user may have used when subscribing.
That is then used when writing messages back to WebSocket clients to
ensure they dont see the internally used, transformed user destination.
This change moves the header name constatn to make it more broadly
applicable. For example SPR-11645.
Prior to this commit, @SubscribeMapping mapped methods (backed with
@SendTo* annotations, or not) would send MESSAGEs with the wrong
destination. Instead of using the original SUBSCRIBE destination, it
would use the lookup path computed from the configured prefixes in the
application.
This commit fixes this issue - now @SubscribeMapping MESSAGEs use the
original SUBSCRIBE destination.
Issue: SPR-11648
This commit validates that the payload type of the message is
assignable to the one declared in the method signature. If that
is not the case, a meaningful exception message is thrown with
the types mismatch.
Prior to this commit, only the Message interface could be defined
in the method signature: it is now possible to define a sub-class
of Message if necessary which will match as long as the Message
parameter is assignable to that type.
Issue: SPR-11584
BufferingStompDecoder message buffer size limit can now be configured
with JavaConfig MessageBrokerRegistry.setMessageBufferSizeLimit() or
with XML <websocket:message-brocker message-buffer-size="">.
Issue: SPR-11527
Before this change the StompDecoder decoded and returned only the first
Message in the ByteBuffer passed to it. So to obtain all messages from
the buffer, one had to loop passing the same buffer in until no more
complete STOMP frames could be decoded.
This chage modifies StompDecoder to return List<Message> after
exhaustively decoding all available STOMP frames from the input buffer.
Also an overloaded decode method allows passing in Map that will be
populated with any headers successfully parsed, which is useful for
"peeking" at the "content-length" header.
This change also adds a BufferingStompDecoder sub-class which buffers
any content left in the input buffer after parsing one or more STOMP
frames. This sub-class can also deal with fragmented messages,
re-assembling them and parsing as a whole message.
Issue: SPR-11527