Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter entites scanned by LocalContainerEntityManagerFactoryBean?

I use Spring Boot, Spring Data JPA and Hibernate.

I need to filter entities which are managed by EntityManager by custom annotation. LocalContainerEntityManagerFactoryBean allows to set a list of packages which are scanned but filters seems to be hardcoded in DefaultPersistenceUnitManager.

Otherwise LocalSessionFactoryBuilder (Hibernate specific) has this feature (method setEntityTypeFilters) but can't be used with Spring Data JPA Repositories which require EntityManagerFactory.

How can I apply entity filtering to LocalContainerEntityManagerFactoryBean?

like image 570
Rafał Ch. Avatar asked Sep 27 '22 05:09

Rafał Ch.


1 Answers

I had a similar problem: I want to "exclude" some Entities while still using package scanning provided by LocalContainerEntityManagerFactoryBean. In my case, I wanted to make use of @Profile(...) annotation used by spring since I need certain entities only if a specific profile is active. I solved it by implementing a PersistenceUnitPostProcessor which removes classes that were added by the scanner. It might not be the most elegant solution, but it works (Spring 4.1.2).

public class ProfileAwarePersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {

    @Autowired
    Environment environment;

    /**
     * Post process the persistence unit and remove Entity classes that require a specific spring profile
     * if profile is not active.
     * 
     * @param pui The persistence unit that was put together so far.
     * @see org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor#postProcessPersistenceUnitInfo(org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo)
     */
    @Override
    public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
        // Check for null to be sure.
        if (pui.getManagedClassNames() != null) {
            Iterator<String> iterator = pui.getManagedClassNames().iterator();
            while (iterator.hasNext()) {
                String className = iterator.next();
                try {
                    Class<?> entityClass = Class.forName(className);
                    Profile profileAnnotation = entityClass.getAnnotation(Profile.class);
                    if (profileAnnotation != null) {
                        String[] requiredProfiles = profileAnnotation.value();
                        if (!environment.acceptsProfiles(requiredProfiles)) {
                            Logging.debug("Removing class " + className + " from persistence unit since none of the required profiles is active "
                                    + StringUtils.join(", ", requiredProfiles));
                            iterator.remove();
                        }
                    }
                } catch (ClassNotFoundException e) {
                    // Something must have gone wrong during scanning if class is suddenly not found anymore.
                    Logging.warn("Class " + className + " not found  while post processing persistence unit.", e);
                }
            }
        }
    }
}

Any other annotation can be used instead of Profile.

like image 65
Daria Avatar answered Oct 03 '22 01:10

Daria