Skip to content

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

Closed
wants to merge 2 commits into from

Conversation

artembilan
Copy link
Member

Fixes #3114

The contract of SpEL with its
getValue(EvaluationContext context, @Nullable Object rootObject) is
that we need to deal with provided rootObject even if it is null
and don't consult with context.getRootObject()

  • Fix ExpressionEvalMap to have an internal rootExplicitlySet
    to indicate that root explicitly provided by consumer, even if it is null.
    According this flag call respective Expression.getValue()
  • Add @Nullable to methods and their arguments into ExpressionEvalMap
    & FunctionExpression to honor Expression contracts
  • Populate an HttpEntity explicitly into ExpressionEvalMap from the
    HttpRequestHandlingEndpointSupport and WebFluxInboundEndpoint for
    full picture

Fixes spring-projects#3114

The contract of SpEL with its
`getValue(EvaluationContext context, @nullable Object rootObject)` is
that we need to deal with provided `rootObject` even if it is `null`
and don't consult with `context.getRootObject()`

* Fix `ExpressionEvalMap` to have an internal `rootExplicitlySet`
to indicate that `root` explicitly provided by consumer, even if it is null.
According this flag call respective `Expression.getValue()`
* Add `@Nullable` to methods and their arguments into `ExpressionEvalMap`
& `FunctionExpression` to honor `Expression` contracts
* Populate an `HttpEntity` explicitly into `ExpressionEvalMap` from the
`HttpRequestHandlingEndpointSupport` and `WebFluxInboundEndpoint` for
full picture
Copy link
Contributor

@garyrussell garyrussell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments; need a test with explicit null root.

* }
* })
* }
* })
* .build();
Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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.

this.context = context;
this.root = root;
this.rootExplicitlySet = rootExplicitlySet;
Copy link
Contributor

Choose a reason for hiding this comment

The 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 null.

is that we need to deal with provided rootObject even if it is null

When I changed the HRHES to .withRoot(null) BOOM!!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct: it is exactly what SpEL contract does in the getValue(EvaluationContext context, @Nullable Object rootObject).
If you explicitly provide a root as null, then it is used as is, without any consultation with context.

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 null

Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right if (s)he provides a null explicitly, but in our case we just miss the proper root to propagate.
See all the Expression.getValue() with root - it is @Nullable. Therefore without checking for null it is really going to lead into NPE.
But in our case we provide all the stuff for expression environment, therefore it is safe not check because we guarantee now a non-null root.
See changes in those HTTP components.

@garyrussell
Copy link
Contributor

Merged as 516ecbc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NULL HttpEntity in headerFunction in HTTP inbound gateway
2 participants