NullPointerException getting hibernate session - java

I am trying to integrate Hibernate 5.2.12 into my Spring application but am getting a nullPointerException when get a session.
Here is the Hibernate configuration
#Configuration
#EnableTransactionManagement
public class HibernateConfig {
#Bean
public LocalSessionFactoryBean sessionFactory() {
System.out.println("Session factory called!");
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
"com.app.persistence.model");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/appDatabase?useSSL=false");
dataSource.setUsername("root");
dataSource.setPassword("password");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "");
hibernateProperties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return hibernateProperties;
}
}
Here is the my util class where sessionFactory is #AutoWired
public class AppHibernateUtil {
private static final AppHibernateUtil instance = new AppHibernateUtil();
#Autowired
private SessionFactory sessionFactory;
public static Session getSession() {
return getInstance().sessionFactory.openSession();
}
private static AppHibernateUtil getInstance() {
return instance;
}
}
Here's my attempted usage of a session
public static String getRoles() {
System.out.println("Custom: getRoles() called");
List<RoleEntity> roles = new ArrayList<>();
try(Session session = AppHibernateUtil.getSession()){
roles = session.createQuery("from RoleEntity").list();
}
return gson.toJson(roles.size());
}
public static void main(String args[]) {
System.out.println(getRoles());
}
The null exception is thrown here
return getInstance().sessionFactory.openSession();
This line never gets outputted at the console
System.out.println("Session factory called!");
If I ignore the AppHibernateUtil class by creating a test class which injects (or not) the sessionFactory. I get the same NPE
#Component
public class TestController {
private static Gson gson = new Gson();
#Autowired
private static SessionFactory sessionFactory;
public static String getRoles() {
System.out.println("Custom: getRoles() called");
List<RoleEntity> roles = new ArrayList<>();
try(Session session = sessionFactory.getCurrentSession()){
roles = session.createQuery("from RoleEntity").list();
}
return gson.toJson(roles.size());
}
public static void main(String args[]) {
System.out.println(getRoles());
}
}

Problem is not in your hibernate configuration, but in your dependency injection.
You are creating manually singleton of AppHibernateUtil (you are calling new AppHibernateUtil()), let Spring do its job and annotate AppHibernateUtil with #Component (default scope of component is Singleton), then inject it into you class, where is your session needed.

My guess is that the NPE is being thrown because the sessionFactory in the getSession() method is null.
This means that Spring is not injecting an instance of SessionFactory.
That may be because you've chosen to implemented the AppHibernateUtil as a singleton. I won't disgress into a discussion about that, except that's it's relevant to point out that Spring is based on dependency injection and using singletons goes against that approach.
If you want to keep using a singleton, you may have success with additional annotations on the AppHibernateUtil class:
#Configuration
#ComponentScan("com.your.package.HibernateConfig")
public class AppHibernateUtil {
...
}
However, as described in the docs, it would probably be best to refactor the AppHibernateUtil class so that it was not a singleton:
#Configuration
public class AppHibernateUtil {
private final AppConfig appConfig;
public AppHibernateUtil(AppConfig appConfig) {
this.appConfig = appConfig;
}
}

Related

JDBC Spring data #Transactional not working

I'm using springboot and spring-data-jdbc.
I wrote this repository class
#Repository
#Transactional(rollbackFor = Exception.class)
public class RecordRepository {
public RecordRepository() {}
public void insert(Record record) throws Exception {
JDBCConfig jdbcConfig = new JDBCConfig();
SimpleJdbcInsert messageInsert = new SimpleJdbcInsert(jdbcConfig.postgresDataSource());
messageInsert.withTableName(record.tableName()).execute(record.content());
throw new Exception();
}
}
Then I wrote a client class that invokes the insert method
#EnableJdbcRepositories()
#Configuration
public class RecordClient {
#Autowired
private RecordRepository repository;
public void insert(Record r) throws Exception {
repository.insert(r);
}
}
I would expect that no record are insert to db when RecordClient's insert() method is invoked, because RecordRespository's insert() throws Exception. Instead the record is added however.
What am I missing?
EDIT. This is the class where I configure my Datasource
#Configuration
#EnableTransactionManagement
public class JDBCConfig {
#Bean
public DataSource postgresDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/db");
dataSource.setUsername("postgres");
dataSource.setPassword("root");
return dataSource;
}
}
You have to inject your datasource instead of creating it manually. I guess because #Transactional only works for Spring managed beans. If you create a datasource instance by calling new constructor (like this new JDBCConfig(). postgresDataSource()), you are creating it manually and it's not a Spring managed beans.
#Repository
#Transactional(rollbackFor = Exception.class)
public class RecordRepository {
#Autowired
DataSource dataSource;
public RecordRepository() {}
public void insert(Record record) throws Exception {
SimpleJdbcInsert messageInsert = new SimpleJdbcInsert(dataSource);
messageInsert.withTableName(record.tableName()).execute(record.contents());
throw new Exception();
}
}

Unable to autowire service in extended java class, throwing NullPointerException

I'm trying to Autowire service inside java class which is extended from TimerTask. This Returning null value while trying to return service in java class. This is the class in which I'm trying to Autowire service:
#Component
public class Task extends TimerTask
{
#Autowired
FileDetailsService fileDetailsService;
int count = 1;
#Override
public void run()
{
fileDetailsService.updateProcessingStatus(fileAudit);
}
Configuration classes: There is no web.xml.....I have configured in java using spring 4
//DataConfig.java
#Configuration
#MapperScan("com.fileC.mapper")
public class DataConfig {
#Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(oracle.jdbc.driver.OracleDriver.class);
dataSource.setUsername("username");
dataSource.setUrl("jdbc***thin**sample **url");
dataSource.setPassword("****");
return dataSource;
}
#Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setTypeAliasesPackage("com.fileC.model");
return sessionFactory;
}
//ApplConfig.java
#Configuration
#ComponentScan(basePackages="com.filec")
public class ApplConfig {
#Bean
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
}
I'm using Spring4, java1.8, ibatis, SQL database.
Here is the service class,
#Service("fileDetailsService")
#Transactional
public class FileDetailsServiceImpl implements FileDetailsService{
private static Logger logger = LoggerFactory.getLogger(FileDetailsServiceImpl.class);
#Autowired
FileDetailsMapper fileDetailsMapper;
#Override
public void insertFileInfo(Details details){
fileDetailsMapper.insertDetails(details);
}
Here is the exception details,
fileAuditMapper>>>>null
Exception in thread "Timer-9" java.lang.NullPointerException at com.filecompare.service.Task.run(Task.java:117)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Please, let me know if I need to add something in config.

I can not Inject Spring Beans into Test using TestNG launcher (Multithreading)

#TransactionConfiguration
#Transactional
#ContextConfiguration(classes=AnnotationConfigContextLoaderUtils.class)
#WebAppConfiguration
#RunWith(SpringJUnit4ClassRunner.class)
public class AnyTest extends TestMachine {
#Inject
private AccountDao accDao; //ALLWAYS NULL
I run the test with:
TestNG testNG = new TestNG();
AppConfig.java
#Bean
public SessionScope sessionScope(){
return new SessionScope();
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public JdbcTemplate jdbcTemplate() throws ConfigurationException {
return new JdbcTemplate(dataSource());
}
#Bean
public DataSource dataSource() throws ConfigurationException {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
//DB INITIALIZE
}
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory() throws ConfigurationException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("package.model");
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager transactionManager() throws ConfigurationException {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", hibernateAuto);
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.show_sql", showSQL);
return properties;
}
SpringMVCInitializer.java
public class SpringMVCInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {AppConfig.class, SpringMVCConfiguration.class, SimpleCORSFilter.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Maven dependency versions:
<spring-version>4.0.3.RELEASE</spring-version>
<spring-test>4.0.3.RELEASE</spring-test>
<testNG-Version>6.9.4</testNG-Version>
<hibernate.version>4.1.5.Final</hibernate.version>
<hibernate-validator>4.2.0.Final</hibernate-validator>
<mysql.connector.version>5.1.32</mysql.connector.version>
<dbcp.version>1.4</dbcp.version>
Why I can't inject any bean to a test?
Note: I used #Autowired and it did not work too.
One sugestion is inject the session in the main method I used to run the test.
Is any way to make this?
I resolved this problem creating a Static Class and injecting the dependencies into this class in a controller.
Controller:
#Controller
public class InitController {
#Inject
public InitController(TestDao testDao, InsynctivePropertyDao propertyDao, ServletContext servletContext, AccountDao accDao, CrossBrowserAccountDao crossDao, CreatePersonFormDao createPersonFormDao, TestSuiteDao testSuiteDao) {
HibernateUtil.init(testDao, propertyDao, servletContext, accDao, crossDao, createPersonFormDao, testSuiteDao);
}
}
HibernateUtil.java
public class HibernateUtil {
public static CrossBrowserAccountDao crossDao;
public static TestDao testDao;
public static synchronized void init(TestDao testDao, InsynctivePropertyDao propertyDao, ServletContext servletContext, AccountDao accDao, CrossBrowserAccountDao crossDao, CreatePersonFormDao createPersonFormDao, TestSuiteDao testSuiteDao){
HibernateUtil.crossDao = crossDao;
HibernateUtil.testDao = testDao;
}
}

(Spring MVC + Hibernate 4 + Test 4) autowired DAO return NULL

Maven Dependencies
<!-- SPRING MVC -->
<spring-version>4.0.3.RELEASE</spring-version>
<spring-test-version>4.2.1.RELEASE</spring-test-version>
<!-- TESTS -->
<junit-Version>4.11</junit-Version>
<!-- DATA BASE -->
<hibernate.version>4.1.5.Final</hibernate.version>
<hibernate-validator>4.2.0.Final</hibernate-validator>
<mysql.connector.version>5.1.32</mysql.connector.version>
AccountDao.java
#Repository
#Transactional
public class AccountDao {
private final SessionFactory sessionFactory;
#Inject
public AccountDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
[...]
}
Test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringMVCInitializer.class}, loader=AnnotationConfigContextLoader.class)
public class LoadingTests extends TestMachine {
#Autowired
private AccountDao accountDao;
AppConfig.java
#Configuration
#PropertySource("classpath:application.properties")
#ComponentScan(basePackages = "company")
#EnableTransactionManagement
public class AppConfig {
#Bean
public AccountDao accountDao() {
return new AccountDao();
}
#Bean
public PropertySourcesPlaceholderConfigurer propertyPlaceHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(dataSource());
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
/*LOCAL*/
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/compamny");
dataSource.setUsername("root");
dataSource.setPassword("");
return dataSource;
}
#Bean(name = "sessionFactory")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan("insynctive.model");
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(Environment.HBM2DDL_AUTO, "create");
properties.put(Environment.DIALECT, "org.hibernate.dialect.MySQLDialect");
properties.put(Environment.SHOW_SQL, true);
return properties;
}
}
SpringMVCConfiguration.java
#Configuration
#EnableWebMvc
#ComponentScan(basePackages="company.controller")
public class SpringMVCConfiguration extends WebMvcConfigurerAdapter {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolverJSP = new InternalResourceViewResolver();
viewResolverJSP.setOrder(1);
viewResolverJSP.setViewClass(JstlView.class);
viewResolverJSP.setPrefix("views/jsp/");
viewResolverJSP.setSuffix(".jsp");
return viewResolverJSP;
}
}
SpringMVCInitializer.java
public class SpringMVCInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {AppConfig.class, SpringMVCConfiguration.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
My autowired of AccountDao is returning null Why? but in my web application everything works good.
I Try lot of things like:
Create a new sessionFactory but doesn't work.
Used: classes ={AppConfig.class,SpringMVCConfig.class}.
Used: #ContextConfiguration(initializers = {SpringMVCInitializer.class}, loader=AnnotationConfigContextLoader.class) throw Type mismatch: cannot convert from Class to Class>
Used: #SpringApplicationConfiguration(classes = {SpringMVCInitializer.class})
I think you need to set initializers instead of classes on your LoadingTests class.
#ContextConfiguration(initializers = {SpringMVCInitializer.class}, loader=AnnotationConfigContextLoader.class)
Also please consider using constructor injection on your DAO.
Since you have #Repository you should include them with
#EnableJpaRepositories(basePackages="yourrepositories") at your config class
try adding
#WebAppConfiguration
before you test class.
The mere presence of #WebAppConfiguration on a test class ensures that a
WebApplicationContext will be loaded for the test using a default for
the path to the root of the web application.
I resolved this making a HibernateUtils to create a sessionFactory.

org.hibernate.HibernateException: createQuery is not valid without active transaction #scheduled

I am using scheduled task to update my database like this:
public interface UserRatingManager {
public void updateAllUsers();
}
#Service
public class DefaultUserRatingManager implements UserRatingManager {
#Autowired
UserRatingDAO userRatingDAO;
#Override
#Transactional("txName")
public void updateAllUsers() {
List<String> userIds = userRatingDAO.getAllUserIds();
for (String userId : userIds) {
updateUserRating(userId);
}
}
}
public interface UserRatingDAO extends GenericDAO<UserRating, String> {
public void deleteAll();
public List<String> getAllUserIds();
}
#Repository
public class HibernateUserRatingDAO extends BaseDAO<UserRating, String> implements UserRatingDAO {
#Override
public List<String> getAllUserIds() {
List<String> result = new ArrayList<String>();
Query q1 = getSession().createQuery("Select userId from UserRating");
}
}
I configured the persistence like this:
#Configuration
#ComponentScan({ "com.estartup" })
#PropertySource("classpath:jdbc.properties")
#EnableTransactionManagement
#EnableScheduling
public class PersistenceConfig {
#Autowired
Environment env;
#Scheduled(fixedRate = 5000)
public void run() {
userRatingManager().updateAllUsers();
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource(env.getProperty("connection.url"), env.getProperty("connection.username"), env.getProperty("connection.password"));
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
return driverManagerDataSource;
}
public PersistenceConfig() {
super();
}
#Bean
public UserRatingUpdate userRatingUpdate() {
return new UserRatingUpdate();
}
#Bean
public UserRatingManager userRatingManager() {
return new DefaultUserRatingManager();
}
#Bean
public LocalSessionFactoryBean runnableSessionFactory() {
LocalSessionFactoryBean factoryBean = null;
try {
factoryBean = createBaseSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
return factoryBean;
}
private LocalSessionFactoryBean createBaseSessionFactory() throws IOException {
LocalSessionFactoryBean factoryBean;
factoryBean = new LocalSessionFactoryBean();
Properties pp = new Properties();
pp.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
pp.setProperty("hibernate.max_fetch_depth", "3");
pp.setProperty("hibernate.show_sql", "false");
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan(new String[] { "com.estartup.*" });
factoryBean.setHibernateProperties(pp);
factoryBean.afterPropertiesSet();
return factoryBean;
}
#Bean(name = "txName")
public HibernateTransactionManager runnableTransactionManager() {
HibernateTransactionManager htm = new HibernateTransactionManager(runnableSessionFactory().getObject());
return htm;
}
}
However, when I get to:
Query q1 = getSession().createQuery("Select userId from UserRating");
in the above HibernateUserRatingDAO I get an exception:
org.hibernate.HibernateException: createQuery is not valid without active transaction
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
at com.sun.proxy.$Proxy63.createQuery(Unknown Source)
at com.estartup.dao.impl.HibernateUserRatingDAO.getAllUserIds(HibernateUserRatingDAO.java:36)
How can I configure to include my scheduled tasks in transactions ?
EDITED:
Here is the code for BaseDAO
#Repository
public class BaseDAO<T, ID extends Serializable> extends GenericDAOImpl<T, ID> {
private static final Logger logger = LoggerFactory.getLogger(BaseDAO.class);
#Autowired
#Override
public void setSessionFactory(SessionFactory sessionFactory) {
super.setSessionFactory(sessionFactory);
}
public void setTopAndForUpdate(int top, Query query){
query.setLockOptions(LockOptions.UPGRADE);
query.setFirstResult(0);
query.setMaxResults(top);
}
EDITED
Enabling Spring transaction prints the following log:
DEBUG [pool-1-thread-1] org.springframework.transaction.annotation.AnnotationTransactionAttributeSource - Adding transactional method 'updateAllUsers' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; 'txName'
What is happening in this case is that since you are using userRatingManager() inside the configuration (where the actual scheduled method exists), the proxy that Spring creates to handle the transaction management for UserRatingUpdate is not being used.
I propose you do the following:
public interface WhateverService {
void executeScheduled();
}
#Service
public class WhateverServiceImpl {
private final UserRatingManager userRatingManager;
#Autowired
public WhateverServiceImpl(UserRatingManager userRatingManager) {
this.userRatingManager = userRatingManager;
}
#Scheduled(fixedRate = 5000)
public void executeScheduled() {
userRatingManager.updateAllUsers()
}
}
Also change your transaction manager configuration code to:
#Bean(name = "txName")
#Autowired
public HibernateTransactionManager runnableTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager htm = new HibernateTransactionManager();
htm.setSessionFactory(sessionFactory);
return htm;
}
and remove factoryBean.afterPropertiesSet(); from createBaseSessionFactory
As I already mentioned, I used your code and created a small sample that works for me. Judging by the classes used, I assumed you are using Hibernate Generic DAO Framework. It's a standalone sample, the main() class is Main. Running it you can see the transactional related DEBUG messages in logs that show when a transaction is initiated and committed. You can compare my settings, jars versions used with what you have and see if anything stands out.
Also, as I already suggested you might want to look in the logs to see if proper transactional behavior is being used and compare that with the logs my sample creates.
I tried to replicate your problem so I integrated it in my Hibernate examples on GitHub:
You can run my CompanySchedulerTest and see it's working so this is what I did to run it:
I made sure the application context is aware of our scheduler
<task:annotation-driven/>
The scheduler is defined in its own bean:
#Service
public class CompanyScheduler implements DisposableBean {
private static final Logger LOG = LoggerFactory.getLogger(CompanyScheduler.class);
#Autowired
private CompanyManager companyManager;
private volatile boolean enabled = true;
#Override
public void destroy() throws Exception {
enabled = false;
}
#Scheduled(fixedRate = 100)
public void run() {
if (enabled) {
LOG.info("Run scheduler");
companyManager.updateAllUsers();
}
}
}
My JPA/Hibernate configs are in applicationContext-test.xml and they are configured for JPA according to the Spring framework indications, so you might want to double check your Hibernate settings as well.

Categories