Enable no-proxy behaviour for all FetchType.LAZY non-collections by default in Hibernate

前端 未结 1 874
礼貌的吻别
礼貌的吻别 2021-02-13 12:21

When using standard JPA annotations, you can specify FetchType.LAZY on non-collection fields (i.e. @ManyToOne and @OneToOne). It seems Hib

相关标签:
1条回答
  • 2021-02-13 12:30

    Ok, I gave up receiving an answer. I carefully examined Hibernate source code and made conclusion that Hibernate itself has no property to achieve what I wish to. But I came up with a little dirty hack, that gives me exactly what I want. So, here it is:

    public class DirtyHackedHibernatePersistence extends HibernatePersistence {
        @Override
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public EntityManagerFactory createEntityManagerFactory(String persistenceUnitName,
                Map properties) {
            properties.put(AvailableSettings.PROVIDER, HibernatePersistence.class.getName());
            Ejb3Configuration cfg = new Ejb3Configuration().configure(persistenceUnitName, properties);
            if (cfg == null) {
                return null;
            }
            cfg.buildMappings();
            hackConfiguration(cfg);
            return cfg.buildEntityManagerFactory();
        }
    
        @Override
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info,
                Map properties) {
            properties.put(AvailableSettings.PROVIDER, HibernatePersistence.class.getName());
            Ejb3Configuration cfg = new Ejb3Configuration().configure(info, properties);
            if (cfg == null) {
                return null;
            }
            cfg.buildMappings();
            hackConfiguration(cfg);
            return cfg.buildEntityManagerFactory();
        }
    
        private void hackConfiguration(Ejb3Configuration cfg) {
            System.out.println("Hacking configuration");
            String noProxyByDefault = cfg.getProperties().getProperty("hibernate.hack.no-proxy-by-default", "false");
            if (Boolean.parseBoolean(noProxyByDefault)) {
                Iterator<?> iter = cfg.getClassMappings();
                while (iter.hasNext()) {
                    hackClass((PersistentClass)iter.next());
                }
            }
        }
    
        private void hackClass(PersistentClass classMapping) {
            Iterator<?> iter = classMapping.getPropertyIterator();
            while (iter.hasNext()) {
                Property property = (Property)iter.next();
                if (property.getValue() instanceof ToOne) {
                    ToOne toOne = (ToOne)property.getValue();
                    if (toOne.isLazy()) {
                        toOne.setUnwrapProxy(true);
                    }
                }
            }
        }
    }
    

    also there must be a resource named META-INF/services/javax.persistence.spi.PersistenceProvider containing a single line with name of the class.

    To use this hack, you should specify the following in a persistence.xml:

    <provider>packagename.DirtyHackedHibernatePersistence</provider>
    <properties>
       <property name="hibernate.hack.no-proxy-by-default" value="true"/>
    </properties>
    

    The full example is available here.

    Note that it if you remove the hibernate.hack.no-proxy-by-default property and rebuild project, both assertions get broken.

    Also I am going to post a feature request to the Hibernate team.

    0 讨论(0)
提交回复
热议问题