Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use method signature to refine RSocket @MessageMapping
Before this change an @MessageMapping could be matched to any RSocket interaction type, which is arguably too flexible, makes it difficult to reason what would happen in case of a significant mismatch of cardinality, e.g. request for Fire-And-Forget (1-to-0) mapped to a method that returns Flux, and could result in payloads being ignored, or not seen unintentionally. This commit checks @ConnectMapping method on startup and rejects them if they return any values (sync or async). It also refines each @MessageMapping to match only the RSocket interaction type it fits based on the input and output cardinality of the handler method. Subsequently if a request is not matched, we'll do a second search to identify partial matches (by route only) and raise a helpful error that explains which interaction type is actually supported. The reference docs has been updated to explain the options. Closes gh-23999
- Loading branch information
1 parent
769a15c
commit 842b424
Showing
12 changed files
with
450 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,13 @@ public class RSocketFrameTypeMessageCondition extends AbstractMessageCondition<R | |
} | ||
|
||
|
||
static final RSocketFrameTypeMessageCondition CONNECT_CONDITION = | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
rstoyanchev
Author
Contributor
|
||
new RSocketFrameTypeMessageCondition(FrameType.SETUP, FrameType.METADATA_PUSH); | ||
|
||
static final RSocketFrameTypeMessageCondition EMPTY_CONDITION = new RSocketFrameTypeMessageCondition(); | ||
This comment has been minimized.
Sorry, something went wrong.
artembilan
Member
|
||
|
||
|
||
|
||
private final Set<FrameType> frameTypes; | ||
|
||
|
||
|
@@ -68,6 +75,10 @@ public RSocketFrameTypeMessageCondition(Collection<FrameType> frameTypes) { | |
this.frameTypes = Collections.unmodifiableSet(new LinkedHashSet<>(frameTypes)); | ||
} | ||
|
||
private RSocketFrameTypeMessageCondition() { | ||
this.frameTypes = Collections.emptySet(); | ||
} | ||
|
||
|
||
public Set<FrameType> getFrameTypes() { | ||
return this.frameTypes; | ||
|
@@ -124,18 +135,71 @@ public int compareTo(RSocketFrameTypeMessageCondition other, Message<?> message) | |
} | ||
|
||
|
||
/** Condition to match the initial SETUP frame and subsequent metadata pushes. */ | ||
public static final RSocketFrameTypeMessageCondition CONNECT_CONDITION = | ||
new RSocketFrameTypeMessageCondition( | ||
FrameType.SETUP, | ||
FrameType.METADATA_PUSH); | ||
/** | ||
* Return a condition for matching the RSocket request interaction type with | ||
* that is selected based on the delcared request and response cardinality | ||
* of some handler method. | ||
* <p>The table below shows the selections made: | ||
* <table> | ||
* <tr> | ||
* <th>Request Cardinality</th> | ||
* <th>Response Cardinality</th> | ||
* <th>Interaction Types</th> | ||
* </tr> | ||
* <tr> | ||
* <td>0,1</td> | ||
* <td>0</td> | ||
* <td>Fire-And-Forget, Request-Response</td> | ||
* </tr> | ||
* <tr> | ||
* <td>0,1</td> | ||
* <td>1</td> | ||
* <td>Request-Response</td> | ||
* </tr> | ||
* <tr> | ||
* <td>0,1</td> | ||
* <td>2</td> | ||
* <td>Request-Stream</td> | ||
* </tr> | ||
* <tr> | ||
* <td>2</td> | ||
* <td>Any</td> | ||
* <td>Request-Channel</td> | ||
* </tr> | ||
* </table> | ||
* @param cardinalityIn -- the request cardinality: 1 for a single payload, | ||
* 2 for many payloads, and 0 if input is not handled. | ||
* @param cardinalityOut -- the response cardinality: 0 for no output | ||
* payloads, 1 for a single payload, and 2 for many payloads. | ||
* @return a condition to use for matching the interaction type | ||
* @since 5.2.2 | ||
*/ | ||
public static RSocketFrameTypeMessageCondition getCondition(int cardinalityIn, int cardinalityOut) { | ||
switch (cardinalityIn) { | ||
case 0: | ||
case 1: | ||
switch (cardinalityOut) { | ||
case 0: return FF_RR_CONDITION; | ||
case 1: return RR_CONDITION; | ||
case 2: return RS_CONDITION; | ||
default: throw new IllegalStateException("Invalid cardinality: " + cardinalityOut); | ||
} | ||
case 2: | ||
return RC_CONDITION; | ||
default: | ||
throw new IllegalStateException("Invalid cardinality: " + cardinalityIn); | ||
} | ||
} | ||
|
||
|
||
private static final RSocketFrameTypeMessageCondition FF_CONDITION = from(FrameType.REQUEST_FNF); | ||
private static final RSocketFrameTypeMessageCondition RR_CONDITION = from(FrameType.REQUEST_RESPONSE); | ||
private static final RSocketFrameTypeMessageCondition RS_CONDITION = from(FrameType.REQUEST_STREAM); | ||
private static final RSocketFrameTypeMessageCondition RC_CONDITION = from(FrameType.REQUEST_CHANNEL); | ||
private static final RSocketFrameTypeMessageCondition FF_RR_CONDITION = FF_CONDITION.combine(RR_CONDITION); | ||
|
||
/** Condition to match one of the 4 stream request types. */ | ||
public static final RSocketFrameTypeMessageCondition REQUEST_CONDITION = | ||
new RSocketFrameTypeMessageCondition( | ||
FrameType.REQUEST_FNF, | ||
FrameType.REQUEST_RESPONSE, | ||
FrameType.REQUEST_STREAM, | ||
FrameType.REQUEST_CHANNEL); | ||
private static RSocketFrameTypeMessageCondition from(FrameType... frameTypes) { | ||
return new RSocketFrameTypeMessageCondition(frameTypes); | ||
} | ||
|
||
} |
Oops, something went wrong.
@rstoyanchev ,
This is braking change.
It was
public
since5.2.0
and Spring Integration relies on this constant: https://build.spring.io/browse/INT-MASTERSPRING40-895/.Anyway even if not SI, some other projects may use it already, therefore breaking change in the current
5.2.2
.Thanks