-
Notifications
You must be signed in to change notification settings - Fork 1.1k
GH-3114: Honor SpEL contract in ExpressionEvalMap #3115
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,8 +51,8 @@ | |
* .usingCallback(new EvaluationCallback() { | ||
* Object evaluate(Expression expression) { | ||
* // return some expression evaluation | ||
* } | ||
* }) | ||
* } | ||
* }) | ||
* .build(); | ||
*} | ||
* </pre> | ||
|
@@ -84,6 +84,7 @@ private ExpressionEvalMap(Map<String, ?> original, EvaluationCallback evaluation | |
* from {@link #original} and returns the result of evaluation using {@link #evaluationCallback}. | ||
*/ | ||
@Override | ||
@Nullable | ||
public Object get(Object key) { | ||
Object value = this.original.get(key); | ||
if (value != null) { | ||
|
@@ -106,9 +107,9 @@ else if (value instanceof String) { | |
|
||
@Override | ||
public Set<Map.Entry<String, Object>> entrySet() { | ||
return this.original.entrySet() | ||
return this.original.keySet() | ||
.stream() | ||
.map(e -> new SimpleImmutableEntry<>(e.getKey(), get(e.getKey()))) | ||
.map((key) -> new SimpleImmutableEntry<>(key, get(key))) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
|
@@ -206,22 +207,35 @@ public interface EvaluationCallback { | |
*/ | ||
public static class ComponentsEvaluationCallback implements EvaluationCallback { | ||
|
||
@Nullable | ||
private final EvaluationContext context; | ||
|
||
@Nullable | ||
private final Object root; | ||
|
||
private final boolean rootExplicitlySet; | ||
|
||
@Nullable | ||
private final Class<?> returnType; | ||
|
||
public ComponentsEvaluationCallback(EvaluationContext context, Object root, Class<?> returnType) { | ||
public ComponentsEvaluationCallback(@Nullable EvaluationContext context, @Nullable Object root, | ||
boolean rootExplicitlySet, @Nullable Class<?> returnType) { | ||
|
||
this.context = context; | ||
this.root = root; | ||
this.rootExplicitlySet = rootExplicitlySet; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear what the purpose of this is; we still get an NPE if the root has explicitly been set to
When I changed the HRHES to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's correct: it is exactly what SpEL contract does in the So, we fix an NPE on our level because we really have a root, but we still don't break SpEL contract when root is explicitly provided as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So you are saying the NPE is ok, because it's in "user" code (in this case, the lambda) so the user is responsible for a null check? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's right if (s)he provides a |
||
this.returnType = returnType; | ||
} | ||
|
||
@Override | ||
public Object evaluate(Expression expression) { | ||
if (this.context != null) { | ||
return expression.getValue(this.context, this.root, this.returnType); | ||
if (this.rootExplicitlySet) { | ||
return expression.getValue(this.context, this.root, this.returnType); | ||
} | ||
else { | ||
return expression.getValue(this.context, this.returnType); | ||
} | ||
} | ||
return expression.getValue(this.root, this.returnType); | ||
} | ||
|
@@ -238,10 +252,15 @@ public static final class ExpressionEvalMapBuilder { | |
|
||
private EvaluationCallback evaluationCallback; | ||
|
||
@Nullable | ||
private EvaluationContext context; | ||
|
||
@Nullable | ||
private Object root; | ||
|
||
private boolean rootExplicitlySet; | ||
|
||
@Nullable | ||
private Class<?> returnType; | ||
|
||
private final ExpressionEvalMapComponentsBuilder evalMapComponentsBuilder = | ||
|
@@ -267,8 +286,9 @@ public ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationConte | |
return this.evalMapComponentsBuilder; | ||
} | ||
|
||
public ExpressionEvalMapComponentsBuilder withRoot(Object root) { | ||
public ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root) { | ||
this.root = root; | ||
this.rootExplicitlySet = true; | ||
return this.evalMapComponentsBuilder; | ||
|
||
} | ||
|
@@ -295,7 +315,8 @@ public ExpressionEvalMap build() { | |
else { | ||
return new ExpressionEvalMap(ExpressionEvalMapBuilder.this.expressions, | ||
new ComponentsEvaluationCallback(ExpressionEvalMapBuilder.this.context, | ||
ExpressionEvalMapBuilder.this.root, ExpressionEvalMapBuilder.this.returnType)); | ||
ExpressionEvalMapBuilder.this.root, ExpressionEvalMapBuilder.this.rootExplicitlySet, | ||
ExpressionEvalMapBuilder.this.returnType)); | ||
} | ||
} | ||
|
||
|
@@ -315,7 +336,7 @@ public ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationConte | |
} | ||
|
||
@Override | ||
public ExpressionEvalMapComponentsBuilder withRoot(Object root) { | ||
public ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root) { | ||
return ExpressionEvalMapBuilder.this.withRoot(root); | ||
} | ||
|
||
|
@@ -340,7 +361,7 @@ public interface ExpressionEvalMapComponentsBuilder extends ExpressionEvalMapFin | |
|
||
ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationContext context); | ||
|
||
ExpressionEvalMapComponentsBuilder withRoot(Object root); | ||
ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root); | ||
|
||
ExpressionEvalMapComponentsBuilder withReturnType(Class<?> returnType); | ||
|
||
|
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.
Change from tabs to spaces has messed up alignment.
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.
Doesn't look like, but I've changed everything into spaces. I don't think tabs are good for JavaDocs.
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.
Right, but you had mixed tabs and spaces here. The indentation is still wrong (extra space before
}
). Will fix on merge.