Hibernate 5.2: SessionFactory, Metadata and NullPointerException

Hello,

In terms of migration to 5.2 I have the following no-XML configuration (except of mappings) stuff:

@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:core.properties" })
@ComponentScan(value = "com.test")
public class HibernateConfiguration {
    private static Logger logger = Logger.getLogger(HibernateConfiguration.class);
    private final static String HIBERNATE_DIALECT = "org.hibernate.dialect.PostgreSQL95Dialect";

    @Autowired private Environment env;
    @Autowired private ResourceLoader resourceLoader;

    @Bean
    public SessionFactory sessionFactory() throws IOException {
        LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
        localSessionFactoryBean.setDataSource(dataSource());
        localSessionFactoryBean.setPackagesToScan(new String[] { "com.test.core.domain.*" });
        localSessionFactoryBean.setMappingLocations(loadResources());
        localSessionFactoryBean.setHibernateProperties(hibernateProperties());
        localSessionFactoryBean.afterPropertiesSet();

        return localSessionFactoryBean.getObject();
    }

    private Resource[] loadResources() {
        Resource[] resources = null;
        try {
            resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader)
                    .getResources("classpath:/hibernate/**/*.hbm.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return resources;
    }

    @Bean
    public DataSource dataSource() {
        ComboPooledDataSource сomboPooledDataSource = new ComboPooledDataSource();
        try {
            сomboPooledDataSource.setDriverClass(Preconditions.checkNotNull(env.getProperty("jdbc.driver-class-name")));
        } catch( PropertyVetoException pve ){
            logger.error("Cannot load datasource driver (" + env.getProperty("jdbc.driver-class-name") +"): " + pve.getMessage());
            return null;
        }

        сomboPooledDataSource.setJdbcUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
        сomboPooledDataSource.setUser(Preconditions.checkNotNull(env.getProperty("jdbc.username")));
        сomboPooledDataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.password")));

        сomboPooledDataSource.setMinPoolSize(20);
        сomboPooledDataSource.setMaxPoolSize(50);
        сomboPooledDataSource.setCheckoutTimeout(15);
        сomboPooledDataSource.setMaxStatements(0);
        сomboPooledDataSource.setIdleConnectionTestPeriod(30);

        return сomboPooledDataSource;
    }

    @Bean
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) throws Exception{
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setSessionFactory(sessionFactory());
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    private static Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", HIBERNATE_DIALECT);
        properties.setProperty("hibernate.bytecode.use_reflection_optimizer", "true");
        properties.setProperty("hibernate.show_sql", "false");
        properties.setProperty("hibernate.hbm2ddl.auto", "validate");
        properties.setProperty("hibernate.default_batch_fetch_size", "1000");
        properties.setProperty("hibernate.max_fetch_depth", "2");
        properties.setProperty("hibernate.generate_statistics", "false");
        properties.setProperty("hibernate.default_schema", "EDRIVE");

        properties.setProperty("hibernate.connection.CharSet", "utf8");
        properties.setProperty("hibernate.connection.characterEncoding", "utf8");
        properties.setProperty("hibernate.connection.useUnicode", "true");
        properties.setProperty("hibernate.connection.release_mode", "after_transaction");

        properties.setProperty("hibernate.jdbc.batch_size", "50");
        properties.setProperty("hibernate.jdbc.fetch_size", "500");
        properties.setProperty("hibernate.jdbc.use_scrollable_resultset", "false");

        properties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory");
        properties.setProperty("hibernate.cache.use_query_cache", "true");
        properties.setProperty("hibernate.cache.use_second_level_cache", "true");
        properties.setProperty("hibernate.cache.use_structured_entries", "false");

        properties.setProperty("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");

        return properties;
    }
}

The NullPointerException raises when I run my test app:

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.hibernate.SessionFactory]: Factory method 'sessionFactory' threw exception; nested exception is java.lang.NullPointerException
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
	at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:579)
	... 75 more
Caused by: java.lang.NullPointerException
	at org.hibernate.metamodel.internal.AttributeFactory.getMetaModelType(AttributeFactory.java:202)
	at org.hibernate.metamodel.internal.AttributeFactory.buildPluralAttribute(AttributeFactory.java:176)
	at org.hibernate.metamodel.internal.AttributeFactory.buildAttribute(AttributeFactory.java:82)
	at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:213)
	at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:220)
	at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:300)
	at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:460)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:710)
	at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:726)
	at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:535)
	at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:519)
	at com.test.core.config.HibernateConfiguration.sessionFactory(HibernateConfiguration.java:46)
	at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$8f9edb09.CGLIB$sessionFactory$2(<generated>)
	at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$8f9edb09$$FastClassBySpringCGLIB$$4b721c9d.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
	at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
	at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$8f9edb09.sessionFactory(<generated>)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
	... 76 more

Where my code is wrong, what should I add (I suppose this is related to Metadata?) to get this working like it was working in the 5.1?

Looks like a Spring issue. Make sure you are using the right Spring or Spring Boot version that is compatible with Hibernate 5.2.

I use the latest versions of Spring & Spring Boot: 5.0.5.RELEASE and 2.0.1.RELEASE correspondingly. Also I use Hibernate 5.2.17.Final.

a regexp as parameter?
scanning of packages is recursive, you don’t need a regexp and I don’t remember ever seen that usage anywhere…
…will be my first suspect…

after checking Spring source code:
LocalSessionFactoryBuilder add the pattern /**/*.class to it and you end up by scanning
classpath*:com/test/core/domain/*/**/*.class

I think you need to add a Spring Jira issue for it. You can try to debug it too. Did you generate the Metamodel classes with the Hibernate 5 tool?

No, this does not work too. The same exception…

Shall I generate Metamodel if I use .hbm mappings?

I am trying now to setup maven-processor-plugin for that but nothing happens - probably because I don’t have annotated classes yet (everything is in the .hbm).

You don’t need to generate the metamodel classes if you don’t use them.

I’ve raised a Spring Jira issue for that: https://jira.spring.io/browse/SPR-16800

Okay, now I have the following picture:

Combination of Spring 4.3.17.RELEASE with Hibernate 5.2.17.Final produces the same exception - NullPointerException in the same place. If I use Spring 5.0.6.RELEASE with Hibernate up to 5.1.14.Final I get exception below:

Caused by: org.hibernate.internal.util.config.ConfigurationException: Could not locate cfg.xml resource [hibernate.cfg.xml]
	at org.hibernate.boot.cfgxml.internal.ConfigLoader.loadConfigXmlResource(ConfigLoader.java:53)
	at org.hibernate.boot.registry.StandardServiceRegistryBuilder.configure(StandardServiceRegistryBuilder.java:163)
	at org.hibernate.boot.registry.StandardServiceRegistryBuilder.configure(StandardServiceRegistryBuilder.java:152)
	at com.test.core.utilities.DatabaseUtilities.setupSessionFactory(DatabaseUtilities.java:173)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:365)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:308)
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:135)

What is wrong with my configuration?

What happens at this line in your code?

@Vlad, Thank you for pointing me to the right direction!

Here was a @PostConstruct (artifacts from previous experiments):

@PostConstruct
public void setupSessionFactory() throws Exception {
    // A SessionFactory is set up once for an application!
    final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
            .configure()
            .build();

    try {
        sessionFactory = new MetadataSources( registry ).buildMetadata().buildSessionFactory();
    } catch (Exception e) {
        // The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
        // so destroy it manually.
        StandardServiceRegistryBuilder.destroy( registry );
    }
}

I’ve removed it and now Hibernate works fine (within Java configuration). But this is still 5.1.14.Final. 5.2.17.Final produces NPE as well:

Caused by: java.lang.NullPointerException
at org.hibernate.metamodel.internal.AttributeFactory.getMetaModelType(AttributeFactory.java:202)
at org.hibernate.metamodel.internal.AttributeFactory.buildPluralAttribute(AttributeFactory.java:176)
at org.hibernate.metamodel.internal.AttributeFactory.buildAttribute(AttributeFactory.java:82)
at org.hibernate.metamodel.internal.MetadataContext.wrapUp(MetadataContext.java:213)
at org.hibernate.metamodel.internal.MetamodelImpl.initialize(MetamodelImpl.java:221)
at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:300)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:462)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:710)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:726)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:535)
at org.springframework.orm.hibernate5.LocalSessionFactoryBean.afterPropertiesSet(LocalSessionFactoryBean.java:519)
at com.test.core.config.HibernateConfiguration.sessionFactory(HibernateConfiguration.java:46)
at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$92f1aca6.CGLIB$sessionFactory$2(<generated>)
at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$92f1aca6$$FastClassBySpringCGLIB$$3e7b3a97.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:361)
at com.test.core.config.HibernateConfiguration$$EnhancerBySpringCGLIB$$92f1aca6.sessionFactory(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 76 more

If you can demonstrate it fails with this template and using your mappings, then it’s a Hibernate issue.

If you can only replicate it with Spring, then it’s a Spring issue.