Hello,
I happily found your spring-filter lib, and tried to use it for my project.
Unfortunately, I came accross a problem when filtering on some related objects.
I use spring-boot 2.5 with spring-data-jpa
I have an entity like
@Entity
UserEntity {
private String username;
@OneToOne(fetch = FetchType.EAGER)
private RoleEntity role;
[...]
}
and use your spec builder in my service with something like
Page<UserEntity> entities = userRepo.findAll(new FilterSpecification<UserEntity>(search), pageable);
And I have some cases that always fails.
search=role.name:'ADMIN'
-> always works
search=role.name:'EDITOR'
-> always fails with the error below, that happens when spring data builds its count query
search=role.name:'EDITOR' and username~'something%'
-> always works when adding another criteria that filters something and reduce the results count
search=role.name:'EDITOR' and username~'noimpact%'
-> always fails with same error when adding another criteria that filters nothing and does not change the results count
From the last 2 cases, I believe the problem comes only when spring chooses to build a new count query.
But when I look at the first 2, I really do not see why one fails and not the other...
Anyway, after debugging failing cases, I found that the RootImpl used in the count query had no Joins, and so that is why RoleEntity is missing in the "from" part of the count query.
So looking at your spec builder, I found that sometimes joins building is bypassed when a join of the same key exists.
Bypassing the check to rebuild joins every time solves the problem, as shown below.
But being rather new on this spring-data-jpa API, I cannot tell if it is a good solution...
So could you have a look please and see if there is something better to do ?
And of course make a fix available if this is a real bug.
Let me know.
Thanks
--- the error I got with the search filters
org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.name' [select count(generatedAlias0) from fr.edf.ssie.api.entity.UserEntity as generatedAlias0 where ( generatedAlias1.name=:param0 ) or ( generatedAlias1.name=:param1 )]; nested exception is java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: 'generatedAlias1.name' [select count(generatedAlias0) from fr.edf.ssie.api.entity.UserEntity as generatedAlias0 where ( generatedAlias1.name=:param0 ) or ( generatedAlias1.name=:param1 )]]
--- the code I changed to solve my problem
ExpressionGeneratorUtils.getDatabasePath(...)
[...]
if (join != null && i < fields.length - 1) {
// FIXME even if the joins map contains the field, call from.join() method to add a join in root.joins, else join will be missing when building query
// if (!joins.containsKey(chain)) {
joins.put(chain, from.join(field, join));
//}
from = joins.get(chain);
}
[...]