Hi there I am trying to create a student webapp with spring boot but i can't seem to get it to run as an error appears every time that hibernate sessionfactory can't be found and i should include a bean type of equal type in my configuration.
I thought I properly configured the webapp properly but i cant seem to get it to find my hibernate session factory which i configured in my DAO, any help on where i'm going wrong would be appreciated.
Here Spring boot launcher class
#SpringBootApplication(exclude = HibernateJpaAutoConfiguration.class)
#ComponentScan({"model", "controller", "dao", "service"})
public class StudentsApplication {
public static void main(String[] args) {
SpringApplication.run(StudentsApplication.class, args);
}
}
Here is my DAO class
#Repository
#Transactional
public class StudentDao {
#Autowired
SessionFactory sessionFactory;
public Student getStudent(final int id) {
#SuppressWarnings("unchecked")
TypedQuery<Student> q = sessionFactory.getCurrentSession().createQuery(
"from student where = id").setParameter("id", id);
return q.getSingleResult();
}
public List<Student> getAllStudents() {
#SuppressWarnings("unchecked")
TypedQuery<Student> q = sessionFactory.getCurrentSession().createQuery(
"from student");
return q.getResultList();
}
public void addStudent(final Student student) {
sessionFactory.getCurrentSession().save(student);
}
public void updateStudent(final Student student) {
sessionFactory.getCurrentSession().saveOrUpdate(student);
}
public void deleteStudent(final int id) {
sessionFactory.getCurrentSession().createQuery(
"delete from student where = id").setParameter("id", id)
.executeUpdate();
}
}
here is my configuration class
#Configuration
#PropertySource({"classpath:application.properties"})
public class DbConfig {
#Autowired
private Environment environment;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getProperty("jdbc.driverClassName"));
dataSource.setUrl(environment.getProperty("jdbc.url"));
dataSource.setUsername(environment.getProperty("jdbc.username"));
dataSource.setPassword(environment.getProperty("jdbc.password"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource());
Properties props = new Properties();
props.put("format_sql", "true");
props.put("hibernate.show_sql", "true");
factoryBean.setHibernateProperties(props);
factoryBean.setPackagesToScan("com.alpheus.students.entity");
// factoryBean.setAnnotatedClasses(Student.class);
return factoryBean;
}
#Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
}
here is my properties file
# Connection url for the database
spring.datasource.url=jdbc:mysql://localhost:3308/week04
spring.datasource.username=user
spring.datasource.password=pass
server.port=9999
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#view resolver
spring.mvc.view.prefix=/views/
spring.mvc.view.suffix=.jsp
here is my controller class
#Controller
public class StudentController {
#Autowired
private StudentService studentService;
#GetMapping("/home")
public String getAllStudents(Model studentsModel) {
List<Student> listStudents = studentService.getAllStudents();
studentsModel.addAttribute("listStudents", listStudents);
return "student-list";
}
#GetMapping("/student/{id}")
public String editStudent(#PathVariable int id, Model studentModel) {
studentModel.addAttribute("student", studentService.getStudent(id));
return "student-form";
}
#PostMapping("/student/new")
public String saveStudent(#ModelAttribute("student")Student student) {
studentService.addStudent(student);
return "redirect:/";
}
#GetMapping("/student")
public String showNewForm() {
return "student-form";
}
#PostMapping("/student/update/{id}")
public String updateStudent(#ModelAttribute("student") Student student) {
studentService.updateStudent(student);
return "redirect:/";
}
#GetMapping(value = "/student/delete/{id}")
public String deleteStudent(#PathVariable int id) {
studentService.deleteStudent(id);
return "redirect:/";
}
}
Related
I am migrating jdbc to hibernate and i have palced below hibernate configuration in my application.
public class HibernateConfiguration {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "com.cm.models" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl(jdbcurl);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show_sql", true);
properties.put("hibernate.format_sql", true);
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
my application interacting fine with database at application startup creating hibernate session successfully through session factory giving output also.
**#Autowired
private SessionFactory sessionFactory;**
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
but after application startup when i hitting DAO by controller then session factory bean getting Null reference and throwing NullPointerException due to which unable to create or open hibernate session , i tried to find out solution but that's not working please let me know why above SessionFactory bean having nullPointer due to which issue created.
Just to test my DAO logic I am using this controller and This controller hitting to DAO where sessionFacory bean is null.
#RestController
#RequestMapping("/Emp")
public class myController {
#RequestMapping(value = "/findByChannelManager", method = RequestMethod.GET)
public void findemp() {
HotelDaoImpl hotelDaoImpl=new HotelDaoImpl();
List <HotelEntity> list = new ArrayList<>();
list = hotelDaoImpl.findByChannelManager (EnumCM.AR);
for (HotelEntity pro : list) {
System.out.println(pro);
}
}
}
#Repository
#Transactional
public class HotelDaoImpl extends AbstractDao implements IHotelDao {
#SuppressWarnings({ "unchecked", "unused" })
#Override
public List<HotelEntity> findByChannelManager(EnumCM cm) {
List<HotelEntity> list = null;
try {
Session s = getSession();
Criteria criteria=s.createCriteria(Hotel.class);
criteria.add(Restrictions.eq("channelManager", "cm.name()"));
list = criteria.list();
}catch(Exception e) {
LOGGER.debug("error " +e.getMessage());
e.printStackTrace();
}
return list;
}
public abstract class AbstractDao {
#Autowired
private SessionFactory sessionFactory;
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
You cant access dao from your controller. You can access dao from service so add service class. Try this code
#RestController
#RequestMapping("/Emp")
public class myController {
#Autowired
HotelService service;
#RequestMapping(value = "/findByChannelManager", method = RequestMethod.GET)
public void findemp() {
List <HotelEntity> list = new ArrayList<>();
list = service.findByChannelManager (EnumCM.AR);
for (HotelEntity pro : list) {
System.out.println(pro);
}
}
}
#Service
#Transactional
public class HotelService {
#Autowired
private HotelDao dao;
public List<HotelEntity> findByChannelManager(EnumCM cm) {
return dao.findByChannelManager(EnumCM cm);
}
}
#Repository
public class HotelDaoImpl extends AbstractDao implements IHotelDao {
#SuppressWarnings({ "unchecked", "unused" })
#Override
public List<HotelEntity> findByChannelManager(EnumCM cm) {
List<HotelEntity> list = null;
try {
Session s = getSession();
Criteria criteria=s.createCriteria(Hotel.class);
criteria.add(Restrictions.eq("channelManager", "cm.name()"));
list = criteria.list();
}catch(Exception e) {
LOGGER.debug("error " +e.getMessage());
e.printStackTrace();
}
return list;
}
public abstract class AbstractDao {
#Autowired
private SessionFactory sessionFactory;
protected Session getSession() {
return sessionFactory.getCurrentSession();
}
}
I wrote this code:
Controller:
#Controller
#RequestMapping("/groups")
public class GroupController {
#Autowired
private GroupService groupService;
#RequestMapping
public String list(Model model) {
model.addAttribute("groups", groupService.getAllGroups());
return "groups";
}
}
dbConnect
public class dbConnect {
public dbConnect(){}
private JdbcTemplate jdbcTemplate;
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void DatabaseConnection(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("org.postgresql.Driver");
driverManagerDataSource.setUrl("jdbc:postgres://xxx");
driverManagerDataSource.setUsername("x");
driverManagerDataSource.setPassword("xss");
this.jdbcTemplate=new JdbcTemplate(driverManagerDataSource);
}
}
Group Repo Interface
public interface GroupRepository {
List<Group> getAllGroups();
}
Group Repo Impl
#Repository
public class InMemoryGroupRepository implements GroupRepository {
public InMemoryGroupRepository(){}
private dbConnect data;
//#Autowired
public InMemoryGroupRepository(dbConnect dbConnect) {
this.data = dbConnect;
}
public List<Group> getAllGroups() {
return data.getJdbcTemplate().query("SELECT id_grupy, nazwa, id_egzaminatora, haslo, egzaminatorzy_id_egzaminatora FROM grupy", new RowMapper<Group>() {
public Group mapRow(ResultSet rs, int rowNum)
throws SQLException {
Group group = new Group();
group.setId_grupy(rs.getInt(1));
group.setNazwa(rs.getString(2));
group.setId_egzaminatora(rs.getInt(3));
group.setHaslo(rs.getString(4));
group.setEgzaminatorzy_id_egzaminatora(rs.getInt(5));
return group;
}
});
}
}
Group Service Interface
public interface GroupService {
List<Group> getAllGroups();
}
Group Service Impl
#Service
public class GroupServiceImpl implements GroupService {
#Autowired
private GroupRepository groupRepository;
public List<Group> getAllGroups() {
return groupRepository.getAllGroups();
}
}
When I try enter "/groups" I get this error:
I think that the problem is that database connection cannot be established. We excluded almost every possible mistake. We tried to use ArrayList instead of using database and it worked well. How can i fix it?
You have an error in your DB configuration. dbConnect class isn't managed by Spring and because of that you get NPE because since it isn't injected into your repository. I suggest using configuration below:
#Configuration
class PersistenceConfig {
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgres://xxx");
dataSource.setUsername("x");
dataSource.setPassword("xss");
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
And repository implementation:
#Repository
public class GroupPostgresRepository implements GroupRepository {
private final JdbcTemplate jdbcTemplate;
public GroupPostgresRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Group> getAllGroups() {
final String sql = "SELECT id_grupy, nazwa, id_egzaminatora, haslo, egzaminatorzy_id_egzaminatora FROM grupy";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
Group group = new Group();
group.setId_grupy(rs.getInt(1));
group.setNazwa(rs.getString(2));
group.setId_egzaminatora(rs.getInt(3));
group.setHaslo(rs.getString(4));
group.setEgzaminatorzy_id_egzaminatora(rs.getInt(5));
return group;
});
}
}
The programmatic configuration seems in place but for some reason the application throws exception:
org.springframework.orm.jpa.JpaSystemException: createQuery is not valid without active transaction; nested exception is org.hibernate.HibernateException: createQuery is not valid without active transaction
Code:
#Repository
public class FilmDAOImpl implements FilmDAO {
#Autowired
private HibernateUtil hibernateUtil;
#Autowired
private SessionFactory sessionFactory;
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
Query searchQuery = sessionFactory.getCurrentSession().createQuery("from Film " +
"join Actor " +
"join Category " +
"where Category.categoryId=:categoryId " +
"and Film.language.id=:languageId " +
"and Film.releaseYear=:releaseYear " +
"and Actor.actorId=:actorId");
searchQuery.setParameter("categoryId", categoryId);
searchQuery.setParameter("languageId", languageId);
searchQuery.setParameter("releaseYear", releaseYear);
searchQuery.setParameter("actorId", actorId);
return (List<Film>)searchQuery.list();
}
}
Configuration:
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories (basePackages = { "com.hibernate.query.performance.persistence" }, transactionManagerRef = "jpaTransactionManager")
#EnableJpaAuditing
#PropertySource({ "classpath:persistence-postgresql.properties" })
#ComponentScan(basePackages = { "com.hibernate.query.performance" })
public class ApplicationConfig {
#Autowired
private Environment env;
public ApplicationConfig() {
super();
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(applicationDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(applicationDataSource());
emf.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(hibernateProperties());
return emf;
}
#Primary
#Bean
public DriverManagerDataSource applicationDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager hibernateTransactionManager() {
final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
transactionManager.setDataSource(applicationDataSource());
return transactionManager;
}
#Bean
public PlatformTransactionManager jpaTransactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
private final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache"));
hibernateProperties.setProperty("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache"));
hibernateProperties.setProperty("hibernate.current_session_context_class", "managed");
hibernateProperties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
return hibernateProperties;
}
}
UPDATE
#Service
#Transactional
public class FilmServiceImpl implements FilmService {
#Autowired
private FilmDAO filmDAO;
#Override
public int createFilm(Film film) {
return filmDAO.createFilm(film);
}
#Override
public Film updateFilm(Film film) {
return filmDAO.updateFilm(film);
}
#Override
public void deleteFilm(int id) {
filmDAO.deleteFilm(id);
}
#Override
public List<Film> getAllFilms() {
return filmDAO.getAllFilms();
}
#Override
public Film getFilm(int id) {
return filmDAO.getFilm(id);
}
#Override
public List<Film> findFilms(int actorId, int categoryId, int languageId, int releaseYear) {
return filmDAO.findFilms(actorId, categoryId, languageId, releaseYear);
}
}
Try using openSession() as below, Since getCurrentSession() just attaches to the current session:
Query searchQuery = sessionFactory.openSession().createQuery(...
Also, you need to surround code with proper try..catch..finally block and in finally close the session using session.close()
I wanted to do commit and rollback using jdbcTemplate.
My question is based on this thread
How do I commit or rollback, should I do it on jdbcTemplate like
jdbcTemplate.commit();
jdbcTemplate.rollback();
Or there are some other ways to achieve commit and rollback functionality using jdbcTemplate.
To call commit or rollback at will set the transactional boundaries programmatically and not declaratively.
For that reason you have to get hold of the PlatformTransactionManager - inject it that is in your DAO and perform the commit/ rollback operation yourself.
Sample code:
#Autowired private JdbcTemplate jdbcTemplate;
#Autowired private PlatformTransactionManager platformTransactionManager;
//..
public void daoMethod(params) {
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
TransactionStatus status=platformTransactionManager.getTransaction(paramTransactionDefinition );
try{
String sqlQuery = "query";
jdbcTemplate.update(sqlQuery, params);
platformTransactionManager.commit(status);
}catch (Exception e) {
platformTransactionManager.rollback(status);
}
Another approach is to get hold of the TransactionTemplate
Sample code:
#Autowired private JdbcTemplate jdbcTemplate;
#Autowired private TransactionTemplate transactionTemplate;
//..
//for operations where query does not return like delete
public void daoMethod(params) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
protected void doInTransactionWithoutResult(TransactionStatus paramTransactionStatus) {
try{
String sqlQuery = "query";
jdbcTemplate.update(query, params);
}catch (Exception e) {
paramTransactionStatus.setRollbackOnly();
}
}
});
}
//for operations where query does return like insert
public int daoMethod(params) {
return transactionTemplate.execute(new TransactionCallback<Integer>() {
public Integer doInTransaction(TransactionStatus paramTransactionStatus) {
String sqlQuery = "query";
Object[] params = params;
int[] types = myTypes;
return jdbcTemplate.update(sqlQuery,params,types);
}
});
}}
Use #Transactional. But of course, before of that, you will have to create bean definition for DataSourceTransactionManager:
// Your DataSource bean definition
#Bean
public DataSource dataSource() {
....
}
// Transaction manager bean definition
#Bean
public DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
And then you can use #Transactional. Example of service:
#Service
public class MyServiceImpl {
#Autowired
private MyDAO myDAO;
#Transactional
public void insert(Entity entity) {
myDAO.insert(entity);
}
}
the easiest way of managing transactions in spring is #Transactional annotation, so your code will look very simple:
#Transactional(rollbackFor = Exception.class)
public void doSomething(...) {
...
}
read more: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
if you have configured the spring transaction manager / jdbcTemplate correctly , then you could always use the #Transactional annotations provided by spring in order to define when you want a transaction to be rolled back or not. But even if you have defined a rollback and your jdbc driver or your database do not allow transactions (check TRANSACTION_ISOLATION over JdbcConnection), then spring will log that is using transactions but the database will simply ignore those points.
#Configuration
public class ConfigurationApp {
#Bean
public DataSource dataSourceJdbc() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
dataSource.setUrl("jdbc:oracle:thin:#localhost:1521:orcl");
dataSource.setUsername("hossein");
dataSource.setPassword("myjava123");
dataSource.setDefaultAutoCommit(false);
return dataSource;
}
#Bean
public JdbcTemplate jdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSourceJdbc());
return jdbcTemplate;
}
#Bean
public DAOImpl dao() {
DAOImpl personDAO = new DAOImpl();
personDAO.setJdbcTemplate(jdbcTemplate());
return personDAO;
}
#Bean
public PersonService personService() {
PersonService personService = new PersonService();
personService.setPersonDAO(dao());
return personService;
}
}
//////////////////////////////////////////
public class Person {
private Integer id;
private String name;
private String family;
private Integer password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFamily() {
return family;
}
public void setFamily(String family) {
this.family = family;
}
public Integer getPassword() {
return password;
}
public void setPassword(Integer password) {
this.password = password;
}
}
/////////////////////////////////////////
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public class DAOImpl {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public int add(Person person) {
String sql = "insert into person(id,name,family,password) values(?,?,?,?)";
return this.jdbcTemplate.update(sql, person.getId(), person.getName(), person.getFamily(), person.getPassword());
}
public void commit(){
BasicDataSource basicDataSource= (BasicDataSource) jdbcTemplate.getDataSource();
basicDataSource.setDefaultAutoCommit(true);
}
}
///////////////////////////////////
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class PersonService {
private DAOImpl personDAO;
public void setPersonDAO(DAOImpl personDAO){
this.personDAO=personDAO;
}
public void addPerson(Person person) {
personDAO.add(person);
this.personDAO.commit();
}
}
///////////////////////
public class MainApp {
public static void main(String[] args) {
Locale.setDefault(Locale.ENGLISH);
AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext(ConfigurationApp.class);
PersonService person=ac.getBean(PersonService.class);
Person person1=new Person();
person1.setId(896);
person1.setName("vali");
person1.setFamily("hassanpoor");
person1.setPassword(12579);
person.addPerson(person1);
}
#Transactional not working in Spring Boot.
Application.java :
#EnableTransactionManagement(proxyTargetClass=true)
#SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
public class Application {
#Autowired
private EntityManagerFactory entityManagerFactory;
public static void main(String[] args) {
System.out.println("--------------------------- Start Application ---------------------------");
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public SessionFactory getSessionFactory() {
if (entityManagerFactory.unwrap(SessionFactory.class) == null) {
throw new NullPointerException("factory is not a hibernate factory");
}
return entityManagerFactory.unwrap(SessionFactory.class);
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "com.buhryn.interviewer.models" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/interviewer");
dataSource.setUsername("postgres");
dataSource.setPassword("postgres");
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.setProperty("hibernate.show_sql", "false");
properties.setProperty("hibernate.format_sql", "false");
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
return properties;
}
}
CandidateDao.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Repository
public class CandidateDao implements ICandidateDao{
#Autowired
SessionFactory sessionFactory;
protected Session getCurrentSession(){
return sessionFactory.getCurrentSession();
}
#Override
#Transactional
public CandidateModel create(CandidateDto candidate) {
CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone());
getCurrentSession().save(candidateModel);
return candidateModel;
}
#Override
public CandidateModel show(Long id) {
return new CandidateModel(
"new",
"new",
"new",
"new");
}
#Override
public CandidateModel update(Long id, CandidateDto candidate) {
return new CandidateModel(
"updated",
candidate.getLastName(),
candidate.getEmail(),
candidate.getPhone());
}
#Override
public void delete(Long id) {
}
}
Service Class
#Service
public class CandidateService implements ICandidateService{
#Autowired
ICandidateDao candidateDao;
#Override
public CandidateModel create(CandidateDto candidate) {
return candidateDao.create(candidate);
}
#Override
public CandidateModel show(Long id) {
return candidateDao.show(id);
}
#Override
public CandidateModel update(Long id, CandidateDto candidate) {
return candidateDao.update(id, candidate);
}
#Override
public void delete(Long id) {
candidateDao.delete(id);
}
}
Controller.class
#RestController
#RequestMapping(value = "/api/candidates")
public class CandidateController {
#Autowired
ICandidateService candidateService;
#RequestMapping(value="/{id}", method = RequestMethod.GET)
public CandidateModel show(#PathVariable("id") Long id) {
return candidateService.show(id);
}
#RequestMapping(method = RequestMethod.POST)
public CandidateModel create(#Valid #RequestBody CandidateDto candidate, BindingResult result) {
RequestValidator.validate(result);
return candidateService.create(candidate);
}
#RequestMapping(value="/{id}", method = RequestMethod.PUT)
public CandidateModel update(#PathVariable("id") Long id, #Valid #RequestBody CandidateDto candidate, BindingResult result) {
RequestValidator.validate(result);
return candidateService.update(id, candidate);
}
#RequestMapping(value="/{id}", method = RequestMethod.DELETE)
public void delete(#PathVariable("id") Long id) {
candidateService.delete(id);
}
}
When I call create method in DAO system throw exception:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException: save is not valid without active transaction; nested exception is org.hibernate.HibernateException: save is not valid without active transaction
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:291)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
My Gradle file :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE")
}
}
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'spring-boot'
jar {
baseName = 'interviewer'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.codehaus.jackson:jackson-mapper-asl:1.9.13")
compile("com.google.code.gson:gson:2.3.1")
compile("org.springframework.data:spring-data-jpa:1.8.0.RELEASE")
compile("org.hibernate:hibernate-entitymanager:4.3.10.Final")
compile("postgresql:postgresql:9.1-901-1.jdbc4")
compile("org.aspectj:aspectjweaver:1.8.6")
testCompile("org.springframework.boot:spring-boot-starter-test")
}
task wrapper(type: Wrapper) {
gradleVersion = '2.3'
}
And link to git repository : https://github.com/Yurii-Buhryn/interviewer
First you are using Spring Boot then use Spring Boot and let that auto configure things for you. It will configure a datasource, entitymanagerfactory, transaction manager etc.
Next you are using the wrong transaction manager, you are using JPA so you should use the JpaTransactionManager instead of the HibernateTransactionManager as that is already configured for you you can simply remove the bean definition for that.
Second your hibernate.current_session_context_class is messing up proper tx integration remove it.
Use auto-config
When you take all this into account you can basically reduce your Application class to the following.
#SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
#EntityScan("com.buhryn.interviewer.models")
public class Application {
public static void main(String[] args) {
System.out.println("--------------------------- Start Application ---------------------------");
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
#Bean
public SessionFactory sessionFactory(EntityManagerFactory emf) {
if (emf.unwrap(SessionFactory.class) == null) {
throw new NullPointerException("factory is not a hibernate factory");
}
return emf.unwrap(SessionFactory.class);
}
}
Next add an application.properties in src/main/resources containing the following.
# DataSource configuration
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/interviewer
# General JPA properties
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.show-sql=false
# Hibernate Specific properties
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.hibernate.ddl-auto=create
This will configure the datasource and JPA correctly.
Use JPA instead of plain Hibernate
Another tip instead of using the plain hibernate API simply use JPA that way you could remove the bean for the SessionFactory as well. Simply change your dao to use an EntityManager instead of a SessionFactory.
#Repository
public class CandidateDao implements ICandidateDao{
#PersistenceContext
private EntityManager em;
#Override
#Transactional
public CandidateModel create(CandidateDto candidate) {
CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone());
return em.persist(candidateModel);
}
#Override
public CandidateModel show(Long id) {
return new CandidateModel(
"new",
"new",
"new",
"new");
}
#Override
public CandidateModel update(Long id, CandidateDto candidate) {
return new CandidateModel(
"updated",
candidate.getLastName(),
candidate.getEmail(),
candidate.getPhone());
}
#Override
public void delete(Long id) {
}
}
Adding Spring Data JPA
And if you really want to benefit add Spring Data JPA into the mix and remove your DAO completely and leave only an interface. What you have now would be moved to a service class (where it belongs IMHO).
The whole repository
public interface ICandidateDao extends JpaRepository<CandidateModel, Long> {}
The modified service (which is now also transactional as it should and all business logic is in the service).
#Service
#Transactional
public class CandidateService implements ICandidateService{
#Autowired
ICandidateDao candidateDao;
#Override
public CandidateModel create(CandidateDto candidate) {
CandidateModel candidateModel = new CandidateModel(candidate.getFirstName(), candidate.getLastName(), candidate.getEmail(), candidate.getPhone());
return candidateDao.save(candidate);
}
#Override
public CandidateModel show(Long id) {
return candidateDao.findOne(id);
}
#Override
public CandidateModel update(Long id, CandidateDto candidate) {
CandidateModel cm = candidateDao.findOne(id);
// Update values.
return candidateDao.save(cm);
}
#Override
public void delete(Long id) {
candidateDao.delete(id);
}
}
Now you can also remove the bean definition for the SessionFactory reducing your Application to just a main method.
#SpringBootApplication(exclude = {ErrorMvcAutoConfiguration.class})
#EntityScan("com.buhryn.interviewer.models")
public class Application {
public static void main(String[] args) {
System.out.println("--------------------------- Start Application ---------------------------");
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
So I would strongly suggest to work with the framework instead of trying to work around the framework. As that will really simplify your developer live.
Dependencies
As a final note I would suggest removing the spring-data-jpa dependency from your dependencies and use the starter instead. The same goes for AspectJ use the AOP starter for that. Also jackson 1 isn't supported anymore so adding that dependency doesn't add anything
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-actuator")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-aop")
compile("com.google.code.gson:gson:2.3.1")
compile("org.hibernate:hibernate-entitymanager:4.3.10.Final")
compile("postgresql:postgresql:9.1-901-1.jdbc4")
testCompile("org.springframework.boot:spring-boot-starter-test")
}