9

Is there any way to define generic filters for Spring data repositories that allow filtering out data, similar to what is available with Hibernate? As an example it would be cool if I could do something like this:

@FilterDef(name = "clientSecurity", defaultCondition = "clientId in (:allowableClients)", parameters = { @ParamDef(name = "allowableClients", type = "Long") })
public interface DocumentRepository extends Repository<Document, Long> {
    public List<Document> findAll();
}

So in the above example, my document repository would only return all documents that belong to client in the set of allowable client ids.

timmy
  • 1,752
  • 6
  • 23
  • 35

1 Answers1

8

I got this working by using custom repository. There is no straightforward way the kind you are expecting as far as I know. Following is what I did on a Comment entity given below.

@Entity
@FilterDef(name="filterByEmail", parameters={@ParamDef(name="email", type="string")})
@Filters( {
    @Filter(name="filterByEmail", condition=":email = email")
} )
public class Comment  {

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     private Long id;

     private String firstname;
     private String lastname;
     private String email;
}

Defined a Repository as follows

@Repository
@Transactional
public interface CommentRepository extends CrudRepository<Comment, Long>,CommentRepositoryCustom {
}

In the custom repository get a handle on the EntityManager and enable session.

public class CommentRepositoryImpl implements CommentRepositoryCustom{

    @PersistenceContext 
    private EntityManager entityManager;

    @Autowired
    private CommentRepository commentRepository;

    @Override
    public Iterable<Comment> findCommentWithEmail(String email) {
        Filter filter = (Filter)entityManager.unwrap(Session.class).enableFilter("filterByEmail");
        filter.setParameter("email", "arun.menon");
        Iterable<Comment> iterable = commentRepository.findAll();
        entityManager.unwrap(Session.class).disableFilter("filterByEmail");
        return iterable;
    }

}

Following is the Test executed.

public void run(String... arg0) throws Exception {
    Iterable<Comment> iterable = commentService.findCommentWithEmail("test@test.com");
    System.out.println("User ois" + iterable);
}

If you need a more generic kind of solution refer here.

ArunM
  • 2,274
  • 3
  • 25
  • 47
  • Works for me. If you are using a service then you need to make it @Transactional – ArunM May 26 '15 at 13:16
  • 2
    Can you think of a method to apply some filter on a Spring Data method if a particular annotation exists on the method, for example something like `@EnalbeFilter("filterName")`? I am looking for a way to apply an interceptor on Spring Data. – Amir Pashazadeh Mar 19 '16 at 09:30
  • 2
    What is `CommentRepositoryCustom` ? – nurettin Oct 14 '18 at 07:46
  • Wouldn't this approach put you at risk of a race condition? What if you have two almost simultaneous concurrent calls with different emails? Wouldn't they both update the same session, enabling the filter with different values, so the findAll() method from one request could return results filtered with the email from the other request? – SnoopDougg Feb 17 '22 at 17:03