Closed spring-projects-issues closed 10 months ago
Juergen Hoeller commented
Rob Winch, I figure this might have to be handled in Spring Security's authorization interceptor, specifically detecting an Optional
return value there and unwrapping it?
Rob Winch commented
Thanks for the report Peter Luttrell
. For example the following fails:
This does fail because Optional
does not have a method of getOrganizationId()
on it.
In this case, if the returned reference isn't present, that
@PostAuthorize
would allow the response,
This is not true. In either case, the PostAuthorize
will fail because Optional
does not have a method getOrganizationId()
Juergen Hoeller I don't think it really makes sense to automatically unwrap Optional
. If the method signature is Optional
, then returnType
should be Optional
. If Optional
is automatically unwrapped, then how would someone use Optional
return types?
Users can always do something like @PostAuthorize("canAccessOrganization(returnObject.orElse(null)?.organiztionId)")
. Finally, if someone really wants to automatically unwrap the returnValue
when it is Optional
, they can override DefaultMethodSecurityExpressionHandler.setReturnObject
.
Mohamed Amine Mrad commented
Hello, I was not able to create an issue. I have a suggestion to add here: In fact SpEL should support writing an Optional properly like writing an Enum. There is an EnumToStringConverter added to DefaultConversionService method addScalarConverters There should be an OptionalToStringConverter also. I'm using thymeleaf and I'm struggling with the ugly get() in HTML.
Stéphane Toussaint commented
I have another use case for this feature request.
I use Spring Integration and some of my service layer bean methods are now returning Optional generic types.
This is a sample of two successive service-activator call, the payload is the Optional\
<int:service-activator expression="@personService.retrieveByUsername(headers.username)" />
<int:service-activator expression="@personService.doWithPerson(payload)" />
The doWithPerson method has not changed ; still waiting for a Person.
Class PersonService {
public void doWithPerson(Person person) {
...
}
}
The retrieveByUsername however now returns an Optional of Person
Class PersonService {
public Optional<Person> retrieveByUsername(String username) {
return Optional.of(...)
}
}
Now Spring Integration (actually the Spring Expression Evaluator) complains it can't find the targeted method with a message like :
Expression evaluation failed: @personService.doWithPerson(payload); nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1004E: Method call: Method doWithPerson(java.util.Optional) cannot be found on PersonService.
Will an OptionalToObjectConverter be feasible ? Maybe it can be possible to rely on Nullable annotation on the target method to handle the Optional.empty() case ?(return null or throw ?).
Another use case is with @PreAuthorize
. Assume a Task
has a reference to a User
and there is a TaskServiceImpl
class with:
Optional<Task> getTask(int taskId);
The controller could check if the task is linked to the authorized user like this:
@DeleteMapping("/{taskId}")
@PreAuthorize("@taskServiceImpl.getTask(#taskId).orElse(null)?.user.id == #userDetails.id")
public String destroy(@AuthenticationPrincipal ApplicationUserDetails userDetails,
@PathVariable("taskId") Integer taskId) {
return "redirect:/tasks";
}
The orElse(null)
is perfect for this, not sure if anything else is needed, but just wanted to let you know about this use case.
My use case would be with @Cacheable
@Cacheable(unless = "#result.isEmpty()")
public Optional<User> getUserById(final String userId);
At the very least, @PreFilter
and @PostFilter
ought to work with Optional
as if they were collections containing at most one object. If the filter sees a non-empty optional but doesn't want to let the contained object through, that becomes an empty optional; the obvious semantics.
This also applies to Thymeleaf templating, which uses SpEL in the default Boot configuration.
+1
Peter Luttrell opened SPR-15878 and commented
This is a feature request to add support for Java 8 Optionals to the Spring Expression Language.
One use case that I just ran into is wanting to use
@PostAuthorize
on a method that returns an Optional in conjunctions with custom expressions. For example the following fails:In this case, if the returned reference isn't present, that
@PostAuthorize
would allow the response, which should be Optional.empty(). If it is present, then it'd be dereferenced into the returnObject, so we'd have direct access to its fields for use in the expression.4 votes, 6 watchers