PropertyPlaceholderConfigurer break my hibernate session - java

I have an issue in my Spring project when, after create my hibernateSession and TransactionManager I initilize a bean that extends PropertyPlaceholderConfigurer
I dont know why but in that moment my hibermnate session is ruin to be used for the rest of my DAO´s. The error that is throwing is this one.
Caused by: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Any suggestions?
I´m trying to extract from database some data to create a properties class and set to a class that I´ve create that extends PropertyPlaceholderConfigurer
This is the class
public class PropertiesSourceImpl extends PropertyPlaceholderConfigurer{
public ConfigurationSource configurationSource;
public Properties properties;
public void init() {
for (ConfigurationProperty prop : configurationSource.getEnabledConfigurationPropertiesByType(ConfigurationProperty.PropertyType.MAIL)) {
System.out.println(prop);
// properties.setProperty(prop.getPropertyKey(), prop.getPropertyValue());
}
}
public Properties getProperties() {
return properties;
}
#Required
public void setConfigurationSource(final ConfigurationSource configurationSource) {
this.configurationSource = configurationSource;
}
}
and here my bean definition
<bean id="propertiesSource" class="nl.greenvalley.digipolis.config.PropertiesSourceImpl" init-method="init">
<property name="configurationSource" ref="configurationSource"/>
</bean>

Finally I found a solution. Instead of use hibernate I just create a new session and transaction before the hibernate session and transaction would be created.
SessionFactory sessionFactory;
public void init() {
Session session = sessionFactory.openSession();
Transaction tx = null;
try {
Properties properties = new Properties();
tx = session.beginTransaction();
List<ConfigurationProperty> dbProperties = session.createCriteria(ConfigurationProperty.class).list();
for (ConfigurationProperty property : dbProperties) {
properties.setProperty(property.getPropertyKey(), property.getPropertyValue());
}
setProperties(properties);
tx.commit();
} finally {
session.close();
}
}

Related

How to solve No qualifying bean of type 'com.luv2code.springdemo.service.CategoriesService'?

I am trying to create a rest api for a categories table. It worked fine when i did it for the customer table. i did everything exactly like i did before but i keep getting this error.
No qualifying bean of type 'com.luv2code.springdemo.service.CategoriesService'
I am using all java configuration for this spring project.
I've tried bunch of answer from the old similar type of question but nothing seems to help
my config class:
#Configuration
#EnableWebMvc
#EnableTransactionManagement
#ComponentScan("com.luv2code.springdemo")
#PropertySource({"classpath:persistence-mysql.properties"})
public class DemoAppConfig implements WebMvcConfigurer {
#Autowired
private Environment env;
private Logger logger = Logger.getLogger(getClass().getName());
// define a bean for ViewResolver
#Bean
public DataSource myDataSource() {
// create connection pool
ComboPooledDataSource myDataSource = new ComboPooledDataSource();
// set the jdbc driver
try {
myDataSource.setDriverClass("com.mysql.jdbc.Driver");
}
catch (PropertyVetoException exc) {
throw new RuntimeException(exc);
}
// for sanity's sake, let's log url and user ... just to make sure we are reading the data
logger.info("jdbc.url=" + env.getProperty("jdbc.url"));
logger.info("jdbc.user=" + env.getProperty("jdbc.user"));
// set database connection props
myDataSource.setJdbcUrl(env.getProperty("jdbc.url"));
myDataSource.setUser(env.getProperty("jdbc.user"));
myDataSource.setPassword(env.getProperty("jdbc.password"));
// set connection pool props
myDataSource.setInitialPoolSize(getIntProperty("connection.pool.initialPoolSize"));
myDataSource.setMinPoolSize(getIntProperty("connection.pool.minPoolSize"));
myDataSource.setMaxPoolSize(getIntProperty("connection.pool.maxPoolSize"));
myDataSource.setMaxIdleTime(getIntProperty("connection.pool.maxIdleTime"));
return myDataSource;
}
private Properties getHibernateProperties() {
// set hibernate properties
Properties props = new Properties();
props.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
props.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
return props;
}
// need a helper method
// read environment property and convert to int
private int getIntProperty(String propName) {
String propVal = env.getProperty(propName);
// now convert to int
int intPropVal = Integer.parseInt(propVal);
return intPropVal;
}
#Bean
public LocalSessionFactoryBean sessionFactory(){
// create session factorys
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
// set the properties
sessionFactory.setDataSource(myDataSource());
sessionFactory.setPackagesToScan(env.getProperty("hibernate.packagesToScan"));
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
// setup transaction manager based on session factory
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
}
here is my Rest controller code:
#RestController
#RequestMapping("/api")
public class CategoriesRestController {
// injecting service through Auto wired
//#Lazy // use this if auto wired gives you issue
#Autowired
private CategoriesService service;
// to send the list of categories on request
#GetMapping("/categories")
public List<Categories> getCategories(){
return service.getCategories();
}
// to GET only one category
#GetMapping("/categories/{categoryID}")
public Categories getCategory(#PathVariable int categoryID) {
Categories categories = service.getCategory(categoryID);
if(categories == null) {
throw new CustomerNotFoundException("Category id not found- "+ categoryID);
}else {
return categories;
}
}
#PostMapping("/categories")
public Categories addCategories(#RequestBody Categories categories) {
// just to make things clear... always set id to 0 when inserting new object
// so that it will be created instead of update
categories.setId(0);
service.saveCategories(categories);
return categories;
}
}
as i've said it says failed to create No qualifying bean of type 'com.luv2code.springdemo.service.CategoriesService' avialabe
The annotation of your config class will be processed, if your configuration class and your main class are in the same directory. If you have it in two separate packages, you have to move the #ComponentScan(basePackages="com.luv2code.springdemo") to top your main class.
Your need to add #Component or #Service at the top of your categoryService too.

How to Update an Entity from a Thread in Dropwizard, Hibernate

I have a thread that waits until a process is complete and then needs to update an entity. But I get
Exception in thread "Thread-22" org.hibernate.HibernateException: No session currently bound to execution context
I have tried opening a new session (see the code below). Session management is normally handled by #UnitOfWork, but this annotation seems to apply only to resources.
public class ConfigDAO extends AbstractDAO<Config>
{
private final SessionFactory sessionFactory;
public ConfigDAO(SessionFactory factory) {
super(factory);
this.sessionFactory = factory;
}
public Config updateFromNewSession(Config config) {
System.out.print("current session: ");
Session session = sessionFactory.openSession();
System.out.println(session);
session.persist(config);
session.close();
return config;
}

How to prevent implicit caching in Spring Boot 1.5.1 Hibernate

I am trying to understand why, after creating a new entity and persisting it whilst the application is running, when retrieving a list of these entities, the new entity should be retrieved from the database, but isn't?
For example:
I created a new entity (from the UI) and persisted it successfully like so:
#Repository
public class BaseDAOHibernate {
Session session;
public BaseDAOHibernate() {
session = HibernateUtils.getSessionFactory().openSession();
}
public void save(Object object) {
Transaction tx = session.beginTransaction();
session.save(object);
tx.commit();
}
...
I verified that the entity is persisted in the database.
Next, when I refresh the UI which lists these entities (for which I added a new one to the database) the new entity is not included and was not retrieved from the following:
#Repository
#SuppressWarnings("unchecked")
public class PasswordDAOHibernate extends BaseDAOHibernate implements PasswordDAO {
#Override
public Collection<Password> getPasswords() {
Query query = session.createQuery("select ...");
return query.list();
}
Here is the interface:
public interface PasswordDAO {
Password getPassword(Integer id);
Collection<Password> getPasswords();
Collection<Password> getPasswords(PasswordSearchParameters params);
Collection<PasswordType> getPasswordTypes();
}
...
Which is called from a controller:
#Controller
public class PasswordsController extends BaseControllerHelper {
#Autowired
private PasswordDAOHibernate passwordDAO;
#RequestMapping("/passwords.htm")
public void passwords(Map model,
HttpServletRequest request) {
Collection<Password> passwords = passwordDAO.getPasswords();
model.put("passwords", passwords);
}
Here is the configuration currently setup:
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.bytecode.use_reflection_optimizer">false</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.connection.url">jdbc:mysql://host:3306/server</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="show_sql">true</property>
<mapping class="com.crm.entity.User"></mapping>
<mapping class="com.crm.entity.Role"></mapping>
<mapping class="com.crm.entity.Property"></mapping>
<mapping class="com.crm.entity.Menu"></mapping>
<mapping class="com.crm.entity.Password"></mapping>
<mapping class="com.crm.entity.PasswordType"></mapping>
</session-factory>
</hibernate-configuration>
HibernateUtils.java
#Component
public class HibernateUtils {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close();
}
}
When I restart the server application the new entity displays in the list.
Is there some kind of implicit caching going on that I need to clear? Note, I have not implemented any explicit caching at this stage.
The problem is your dao, which is flawed in a very dangerous way. A Session isn't thread safe and shouldn't be shared. It should be opened for each action (or at least the current session should be used).
Plain Hibernate Solution
You DAO should look something like this.
private final SessionFactory sessionFactory;
protected BaseDAOHibernate(SessionFactory sessionFactory) {
this.sessionFactory=sessionFactory;
}
protected Session getSession() {
return this.sessionFactory.getCurrentSession();
}
public void save(Object object) {
getCurrentSession().save(object);
}
Now you specific dao should reuse the getSession method.
#Repository
#Transactional
public class PasswordDAOHibernate extends BaseDao implements PasswordDao {
#Autowired
public PasswordDAOHibernate(SessionFactory sessionFactory) {
super(sessionFactory);
}
#Override
public Collection<Password> getPasswords() {
return getSession.query("select ...", Password.class).list();
}
When doing so you probably will run into issues with an error stating that no session can be found due to no transaction (or something along those lines).
To fix this use Spring Boot (and some manual configuration).
First move the hibernate.connection properties to your application.properties and remove them from hibernate.cfg.xml.
spring.datasource.url=jdbc:mysql://host:3306/server
spring.datasource.username=username
spring.datasource.password
Now Spring will create a Datasource for you. Next remove your HibernateUtils and configure the SessionFactory using Springs LocalSessionFactoryBean.
#Bean
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
LocalSessionFactoryBean factory = new LocalSessionFactoryBean();
factory.setDataSource(dataSource);
return factory;
}
You will also need the appropriate transaction manager
#Bean
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
Now due to everything being setup in Spring, the injection of the SessionFactory and the #Transactional you will get a managed Session which will be properly opened and closed for you.
Controller Fix
Your controller is also flawed as you should be injecting a PasswordDao and not the concrete type (which would now fail due the the creation of a proxy for the transactions).
#Controller
public class PasswordsController extends BaseControllerHelper {
#Autowired
private PasswordDAO passwordDAO;
JPA Solution
However while all of this will probably work I would strongly suggest to use JPA and the EntityManager instead of the Session and SessionFactory approach.
To do so remove the LocalSessionFactoryBean and the HibernateTransactionManager and add the remaining properties of the hibernate.cfg.xml to the application.properties.
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.show-sql=true
Next to the spring.datasource properties that is all you need and you can delete the hibernate.cfg.xml file.
Now instead of using the SessionFactory use the EntityManager in your dao.
public abstract class BaseDao {
#PersistenceContext
protected EntityManager em;
public void save(Object o) {
em.persist(o);
}
}
And your specific dao.
#Repository
#Transactional
public PasswordJpaDao extends BaseDao implements PasswordDao {
#Override
public Collection<Password> getPasswords() {
return em.createQuery("select ...", Password.class).getResultList();
}
Spring Data JPA Solution
When using JPA you could even drop your generic dao approach and implementations and use Spring Data JPA instead. Your whole PasswordDao would then look like
public interface PasswordDao extends JpaRepository<Password, Long> {}
All the crud functionality (findAll, findOne, save etc.) is available out-of-the-box. Creating queries is pretty easy and saves you from writing the boilerplate code.
You can use #Cacheable(false) on your entity
or disable the shared cache altogether for all your entities by adding this to your persistence.xml
<shared-cache-mode>NONE</shared-cache-mode>
For Hibernate you can also use
session.setCacheMode(CacheMode.IGNORE);
see this link for more information about the different cache levels in JPA

Spring-boot - add hibernate mapping file to entity manager

I'm migrating legacy app to Spring-boot and have to integrate an hibernate named query mapping file (previously configured in persitence.xml file).
I've come out with a solution with an
...
#Autowired
private DataSource dataSource;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
//...
sessionFactoryBean.setMappingResources("META-INF/named-queries.hbm.xml");
return sessionFactoryBean;
}
But i'm ending having an entityManager bean and a sessionFactory bean in my application!
is it a good solution according to you?
Is there a way to add somehow the hibernate mapping file (named-query.hbm.xml) to the entityManager without using the sessionFactory bean?
Thanks in advance for you suggestions
** EDIT **
fro JB Nizet's suggestion, also come up with another solution
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource);
// ...
entityManagerFactory.setMappingResources("META-INF/named-queries.hbm.xml");
return entityManagerFactory;
}
and in my DAO/Service, i can still get hibernate session with:
private Session getSession() {
//return this.sessionFactory.getCurrentSession();
return this.entityManager.unwrap(Session.class);
}
But if someone nows if we can do the same thing with spring-boot auto-config with properties, it's welcomed!
Put the *.hbm.xml files under the src/main/resources folder and Spring Boot can automatically scan for them.
If you want to specify the location in the application.properties file, define them to the spring.jpa.mapping-resources attribute.
spring.jpa.mapping-resources=hibernate/MyMapping.hbm.xml,hibernate/MyMapping2.hbm.xml
Tested in SpringBoot 2.1.3, following is the folder structure
src/main/resources/hibernate : Store all the *.hbm.xml files
src/main/resources/application.properties : define the spring boot properties
And if you want to get the hibernate session in your Dao classes, define them as follows:
#Repository
#Transactional
public class XxxDao {
#Autowired
private EntityManager entityManager;
private Session getSession() {
return entityManager.unwrap(Session.class);
}
...
}
#Autowired
private ResourceLoader rl;
#Bean
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setMappingLocations(loadResources());
}
public Resource[] loadResources() {
Resource[] resources = null;
try {
resources = ResourcePatternUtils.getResourcePatternResolver(rl)
.getResources("classpath:/hibernate/*.hbm.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return resources;
}

Hibernate Session is closed in spring transaction after calling method second time

First of all I am a beginner in spring.I have created a simple Spring service that has DAO injected and transaction is managed by HibernateTransactionManager of spring, like as below.(And transaction configuration is used using annotations )
#Service(value="daopowered")
public class UserServiceImplDao implements UserService
{
#Inject
private UserDao userDao;
#Override
#Transactional
public User autheticate( String userId, String password )
{
return userDao.findByIdAndPassword(userId, password);
}
My transaction configuration is following
<bean id="txMgr"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txMgr" />
Now the problem is when I call authenticate method first time using some controller then it works fine ( does DB operations successfully) but after calling it again second time hibernate session is closed exception is coming ? Please guide me what I am doing it wrong or how to handle this scenario ? Why wont spring opens a new transaction when I call this method second time ?
Exception Trace:
2013-05-22T21:04:18.041+0530 DEBUG [14208212-2] lerExceptionResolver Resolving exception from handler [com.akhi.store.controller.HomeController#5d9d277e]: org.springframework.orm.hibernate3.HibernateSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed!
2013-05-22T21:04:18.044+0530 DEBUG [14208212-2] tusExceptionResolver Resolving exception from handler [com.akhi.store.controller.HomeController#5d9d277e]: org.springframework.orm.hibernate3.HibernateSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed!
2013-05-22T21:04:18.044+0530 DEBUG [14208212-2] lerExceptionResolver Resolving exception from handler [com.akhi.store.controller.HomeController#5d9d277e]: org.springframework.orm.hibernate3.HibernateSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed!
2013-05-22T21:04:18.046+0530 DEBUG [14208212-2] et.DispatcherServlet Could not complete request
org.springframework.orm.hibernate3.HibernateSystemException: Session is closed!; nested exception is org.hibernate.SessionException: Session is closed!
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:658)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.convertHibernateAccessException(AbstractSessionFactoryBean.java:245)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.translateExceptionIfPossible(AbstractSessionFactoryBean.java:224)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at com.sun.proxy.$Proxy28.findByIdAndPassword(Unknown Source)
EDIT: The DAO code
#Repository
public class UserDaoImpl extends GenericHibernateDAO<User, Long>
implements
UserDao
{
#Override
public User findByIdAndPassword( String id, String password )
{
Criteria crit = getSession().createCriteria(User.class).add(Restrictions.eq("userId",
id)).add(Restrictions.eq("password",
password)).setMaxResults(1);
List<?> list = crit.list();
if (list.size() > 0)
return (User) list.get(0);
else
return null;
}
and getSession() implementation is
protected Session getSession() {
if (session == null) {
session = sessionFactory.getCurrentSession();
}
return session;
}
Also the abstract DAO class has sessionfactory injected
public abstract class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, Long> {
private Class<T> persistentClass;
protected Session session;
#Autowired
private SessionFactory sessionFactory;
Your ObjectDao need a SessionFactory and the annotation Transaction. Something like this :
#Component
public class userDao{
#AutoWired
private SessionFactory sessionFactory;
#Transactional
public User findByIdAndPassword(String id , String password){
....
}
{getters and setters}
}
Dont do that :
protected Session getSession() {
if (session == null) {
session = sessionFactory.getCurrentSession();
}
return session;
}
just return the current session , the Transactional annotation is responsible for opening and closing sessions , like this :
protected Session getSession() {
return sessionFactory.getCurrentSession();
}

Categories

Resources