-
Notifications
You must be signed in to change notification settings - Fork 687
DATACMNS-1026 ExtensionAwareEvaluationContextProvider now returns all overloaded methods as functions #217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…s all overloaded methods as functions. All overloaded methods are now available in SPeL expressions. The key of the Map used for collecting methods is now the name and the length of the argument list. It is also actually a MultiValueMap to allow multiple overloaded methods. Among methods with identical argument list from different sources in the same extension (extension, root object, aliases) the last one in the order in parens wins. If there is more than one method for an application the following rules are applied: If there is one method with exact matching types in the argument list it is used, otherwise an exception is thrown.
Minor improvements to Javadoc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cosmetics. Looks good beyond that.
} | ||
|
||
Optional<Function> exactMatch = candidates.stream().filter(f -> f.supportsExact(argumentTypes)).findFirst(); | ||
if (exactMatch.isPresent()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return exactMatch.orElseThrow(…)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that, but then we return a Function
instead of Optional<Function>
and we end up sooner or later either rewrapping it in an Optional or doing null checks.
What we really need is
ifPresentOrElse
but that is java9
I just removed the else to make it a little lighter on the eye.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. That makes sense. Maybe inverting the check here is an option, too. if (!exactMatch.isPresent()) { throw … }
.
I also wonder: we don't really detect multiple exact matches here, do we? It just barks if we don't find any exact match, right? Actually that renders the exception message wrong as it's only thrown if there's no match at all, not if there are multiple ones matching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct: multiple exact matches are not possible at this point because we drop those when we add elements to Functions
this ensures the behavior of overwriting of methods from different sources (extension, root object, and aliases).
But we only check for an exact match if we have more than one match (candidates). So we throw the exception if we have multiple candidates and can't disambiguate between them.
We could improve the message to:
There are multiple matching methods for arguments of type , but no exact match. Make sure to provide only one matching overload or one with exactly those types.
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But that's not what the code does is it? If we have multiple candidates and have multiple ones that potentially match exactly, we just pick the first one. Is that intended? I thought the idea was to also reject that case, wasn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There can't be multiple exact matches. We don't add them to the Map contained in functions in the first place. see the addAll
methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, now that makes sense. Thanks!
} | ||
} | ||
|
||
@Data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be @Value
instead?
} | ||
|
||
/** | ||
* Checks wither this {@code Function} has the same signature as another {@code Function}. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"whether"
* @param keyFunction {@link Function} to create a key from an element of the {@link java.util.stream.Stream} | ||
* @param valueFunction {@link Function} to create a value from an element of the {@link java.util.stream.Stream} | ||
*/ | ||
public MultiValueMapCollector(Function<T, K> keyFunction, Function<T, V> valueFunction) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RequiredArgsConstructor
? I guess a static factory method in StreamUtils
would align nicely with the ones we have in place for unmodifiable lists and sets.
@Override | ||
public BinaryOperator<MultiValueMap<K, V>> combiner() { | ||
|
||
return (map1,map2) -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Space after comma.
* @author Jens Schauder | ||
* @since 2.0 | ||
*/ | ||
class FunctionsMap { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of a plain Functions
?
*/ | ||
public Map<String, Function> getFunctions() { | ||
FunctionsMap getFunctions() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wonder if it makes sense to extract an interface here so that clients can't modify the instance anymore, i.e. return something that doesn't expose the addAll(…)
methods anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just in a private class anyway. A separate interface sounds like overkill to me in this case.
FunctionsMap functions = adapter.getFunctions(); | ||
|
||
Optional<Function> function = functions.get(name, argumentTypes); | ||
return function.map(FunctionMethodExecutor::new); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inline function
?
.findFirst().map(Entry::getValue).map(FunctionMethodExecutor::new); | ||
FunctionsMap functions = adapter.getFunctions(); | ||
|
||
Optional<Function> function = functions.get(name, argumentTypes); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inline functions
?
@Test // DATACMNS-1026 | ||
public void overloadedMethodsGetResolved() throws Exception { | ||
|
||
provider = new ExtensionAwareEvaluationContextProvider( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shall we extract that setup step? It's repeated in every test below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, I'll take it from here.
…ll overloaded methods as functions. All overloaded methods are now available in SPeL expressions. Among methods with identical argument list from different sources in the same extension (extension, root object, aliases) the last one in the order in parens wins. If there is more than one method for an application the following rules are applied: if there is one method with exact matching types in the argument list it is used, otherwise an exception is thrown. Original pull request: #217.
Minor improvements to Javadoc. Original pull request: #217.
Minor refactorings here in there for clarity. Original pull request: #217.
All overloaded methods are now available in SPeL expressions.
The key of the Map used for collecting methods is now the name and the length of the argument list.
It is also actually a MultiValueMap to allow multiple overloaded methods.
Among methods with identical argument list from different sources in the same extension (extension, root object, aliases) the last one in the order in parens wins.
If there is more than one method for an application the following rules are applied:
If there is one method with exact matching types in the argument list it is used. Otherwise, an exception is thrown.