8

I am using Spring MVC and Hibernate for my web application. I am looking for a way to create a global hibernate filter of sorts that would apply to each query in my DAO classes without me having to explicitly enable it in each DAO method.

The requirement is to filter records by a user selected session variable. So our query parameter would be held in session and all DAO queries in that session need to filter results by this variable. The purpose here is to avoid all the repeatable filtering code in every DAO method.

Any and all ideas are welcome!

Angad
  • 3,389
  • 3
  • 30
  • 40
  • This might help a bit. http://stackoverflow.com/questions/5680750/how-to-enable-hibernate-filter-for-sessionfactory-getcurrentsession – RP- Sep 15 '14 at 19:26
  • I had the same idea. What i find to be a problem that this method does not resolve is that I would have to define the filter in each entity class in my project. Could there be better way so that the filter definition is kept at one place and used by various different entities? – Angad Sep 15 '14 at 19:39
  • 1
    I got what you are saying, I have not tried, but can defining a super class and add the `Filter` in super class extend all your entities with that class may work. – RP- Sep 15 '14 at 19:59
  • @Rp- turns out extending a super class does not work our for this. – Angad Sep 18 '14 at 18:02
  • I think there might be some problems while resolving the properties. Im not sure if we can define Filter on `@Embeddable`, if we can, that would worth a try using `@Embeddable` and `@Embedded` – RP- Sep 18 '14 at 18:49
  • 1
    What I ended up doing is to create a package-info.java file in my entity package and define the filter definition there. All entities then have access to the same definition. – Angad Sep 18 '14 at 18:52
  • Wow.. you thought out-of-the-box. Great thinking. You can add your answer, it might help others – RP- Sep 18 '14 at 19:01

1 Answers1

16

Putting out the way I handled this down here. Below is based on the discussion with @Rp- and suggestions made here.

Three major elements went into configuring this:
- Spring's session scoped beans
- package-info.java
- Spring AOP



I created a session scoped Spring bean that will hold my user selected variable. The variable would get modified upon user's request through a spring Controller mapping method. Being held in a spring managed bean, I have access to the session variable anywhere in my application by virtue of spring's dependency injection.

@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class SessionParam implements Serializable{

  private String sessParam;
..
..
}

Next I define my hibernate filter at package level. This is done in package-info.java file. All entities in this package thus inherit this filter.

 @FilterDef(name="GLOBAL_FILTER",   parameters = {@ParamDef(name="sessParam", type="string")}, 
                                    defaultCondition = "sessParam = :sessParam")

package com.company.app.entity;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.FilterDefs;
import org.hibernate.annotations.ParamDef;


Entities in the package are annotated with hibernate's @Filter annotation as below:

@Entity
@Filter(name="GLOBAL_FILTER")
@Table(name = "TABLE_XYZ", schema = "SCHEMA_ABC")
public class TableXyz implements Serializable {
...
}

Lastly, all DAO queries are intercepted using an AspectJ aspect on hibernate's Session Factory's getCurrentSession() method.

Below is the Aspect class.

@Aspect
@Component
public class GlobalFilter {

    @Autowired
    SessionParam sessionParam;


    @Pointcut("execution(* org.hibernate.SessionFactory.getCurrentSession(..))")
    protected void hibernateSessionFetch(){

    }

    @AfterReturning(pointcut = "hibernateSessionFetch()", returning = "result")
    public void enableGlobalFilter(JoinPoint joinPoint, Object result){

        Session session = (Session) result;

        session.enableFilter("GLOBAL_FILTER").setParameter("sessParam", sessionParam.getSessParam());

    }
}

All queries on entities with "GLOBAL_FILTER" now have a conditional check on the required variable. No explicit conditional checks in each query is required in the DAO methods.

Community
  • 1
  • 1
Angad
  • 3,389
  • 3
  • 30
  • 40
  • Where u will set sessParam? – Volkan Okçu Aug 28 '18 at 15:18
  • 4
    Please be aware that Hibernates @Filter only applies to queries, but not to direct fetching. That means that an em.find() or a repository.findById() is NOT filtered. (Source: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html) – Arigion May 03 '19 at 13:24
  • 1
    @Arigion do you know which other methods besides `findById` are direct fetching? I don't see a list in the docs – aarbor Aug 18 '20 at 16:26