Open sergey-morenets opened 4 days ago
Usage of Config Properties is documented at https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html#jpa.query.spel-expressions at Example 20. Using Value Expressions in Repository Query Methods: Configuration Properties
Let me know what else you're looking for.
For JPA, the evaluation of annotation values is subject to JPA providers, where we cannot inject additional functionality. However, the mentioned page about Value Expressions is part of our common documentation.
Maybe the issue is that we created some over-expectation by our naming. Value Expressions are SpEL expressions plus Property Placeholders whereas we previously only supported SpEL expressions.
This section misses two important topics.
#{tenantService.getOrderCollection()}
But if I try to use it in @Query annotation (productService is bean id):
@Query("""
FROM Product WHERE name=:name
and department=?#{productService.getDepartment()}""")
Product findByName(String name);
then I receive an exception:
org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'productService' cannot be found on object of type 'java.lang.Object[]' - maybe not public or not valid?
So it's not clear whether we can access bean properties/methods in Value Expressions and if yes then how?
Documenting the scope makes sense. For the second issue, it works as designed.
It would make sense to call out that the default root object is the array of query method parameters when working with queries. Any beans must be accessed via ?#{#productService.getDepartment()}
(note the missing #
was added before productService
).
Any other properties, variables and functions must be contributed by declaring a EvaluationContextExtension
as per documentation.
By explaining scopes in the docs, we can make the second case more clear.
@mp911de
Unfortunately your advise didn't help. I added #:
@Query("""
FROM Product WHERE name=:name
and department=?#{#productService.getDepartment()}""")
Product findByName(String name);
But now error is different:
org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method getDepartment() on null context object
Although productService bean is available in the application context.
@mp911de
I investigated and debugged this issue and it seems that it's not possible to access Spring beans using this construction:
?#{#productService.getDepartment()}
There's BeanResolver interface which JavaDocs clearly state that @ or & characters should be used instead of #:
/**
* A bean resolver can be registered with the evaluation context and will kick in
* for bean references: {@code @myBeanName} and {@code &myBeanName} expressions.
*
* <p>The {@code &} variant syntax allows access to the factory bean where relevant.
*
* @author Andy Clement
* @since 3.0.3
*/
@FunctionalInterface
public interface BeanResolver {
So the correct construction is
@Query("""
FROM Product WHERE name=:name
and department=?#{@productService.getDepartment()}""")
Product findByName(String name);
Spring Data 3.4.0 brings new feature - Value Expressions (https://github.com/spring-projects/spring-data-jpa/issues/3619)
However the latest documentation section(https://docs.spring.io/spring-data/jpa/reference/jpa/value-expressions.html) has only one example of the code:
This example is from Spring Data Mongo and can't be used for Spring Data JPA. Moreover the whole section is copied from Spring Data Mongo documentation without any changes (https://docs.spring.io/spring-data/mongodb/reference/mongodb/value-expressions.html)
So neither the documentation nor GitHub ticket have examples how to use new feature in Spring Data JPA. So it'd be nice to add few examples in the documentation.