Before this change the compilation of a method reference or property/field
access was not properly cleaning up the stack if compilation meant
calling a static method or accessing a static field. In these cases there
is no need for a target object on the stack and it should be removed if
present. For a simple expression it is harmless since the end result of
the expression is the thing on the top of the stack, but for nested
expressions if the inner expression suffered this issue, the outer
expression can find itself operating on the wrong element.
The particular issue covered the case of a static field access but this
fix (and associated tests) cover static method, property and field access.
Issue: SPR-13781
JIRA: https://jira.spring.io/browse/SPR-13784
JDK8 and Apache Commons Codec support the RFC 4648
"URL and Filename Safe" Base64 alphabet.
Add methods to `Base64Utils` to support this feature.
General improvements e.g. make use of Java 8 Stream. The main reason
for the refactoring however to tighten error handling. To that extent:
InvocableHandlerMethod turns all exceptions into Reactive Streams
error signals, in effect never allowing any Exceptions to bubble up.
HandlerMethodArgumentResolver may throw an Exception for sync resolution
or produce an error signal via the returned Publisher. Either way the
exception is consistently wrapped with helpful method argument details.
For the latter case using a custom mapError operator.
HandlerMethodArgumentResolver no longer needs to return Optional for
nullable argument values. Instead (for now) the defaultIfEmpty operator
of reactor.rx.Stream operator is used to ensure a default constant value
(called "NO_VALUE") is produced. That way an argument resolver may
produce 0..1 values where 0 means it did not resolve to any value and
that results in null passed as the argument value.
If a HandlerMethodArgumentResolver produces more than one value, all
additional values beyond the first one will be ignored with the help
of a custom "first" operator.
As HandlerMethod is invoked within the map operator, checked exceptions
are not allowed but instead of wrapping it in a runtime exception what
we really need is to unwrap the target exception for exception
resolution purposes. To this end concatMap is used to produce a nested
Publisher or an error Publisher with the unwrapped target exception.
Related to that InvocableHandlerMethod now returns
Publisher<HandlerResult> instead of Publisher<Object> so that no longer
needs to be externally mapped from Object to HandlerResult.
InvocableHandlerMethodTests provides tests for the above scenarios and
verifies the details of resulting error signals.