DAO service layer in jpaRepository - spring

I've been reading Spring Boot tutorials, most of the MVC patterns are implemented based on
1) Dao interface
2) Dao Interface Implementation
3) Service interface for persistence
4) Service implementation
I think this is the good practice and I was working it. Now I try to use JpaRepository which helps to implement easily and efficiently. The configuration of my project is
Configuration class
#Configuration
#PropertySource(value = { "classpath:application.properties" })
#EnableJpaRepositories(value={"com.dept.dao"})
public class ApplicationContextConfig {
#Autowired
private Environment environment;
#Bean(name = "dataSource")
public DataSource getDataSource() {
//DataSource connections
}
private Properties getHibernateProperties() {
//Hibernate properties
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.dept.model" });
sessionFactory.setHibernateProperties(getHibernateProperties());
return sessionFactory;
}
#Autowired
#Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager transactionManager = new HibernateTransactionManager(sessionFactory);
return transactionManager;
}
#Primary
#Bean(name="entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws ClassNotFoundException {
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(getDataSource());
// mention packae scan your classes annotated as #Entity
entityManagerFactoryBean.setPackagesToScan(new String[] { "com.dept.model" });
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setShowSql(true);
entityManagerFactoryBean.setJpaVendorAdapter(vendorAdapter);
entityManagerFactoryBean.setJpaProperties(getHibernateProperties());
entityManagerFactoryBean.afterPropertiesSet();
entityManagerFactoryBean.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
return entityManagerFactoryBean;
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
try {
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
transactionManager.setDataSource(getDataSource());
transactionManager.setJpaDialect(new HibernateJpaDialect());
transactionManager.setJpaProperties(getHibernateProperties());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public JpaVendorAdapter japAdapter(){
return new HibernateJpaVendorAdapter();
}
}
Example I need to save this object in database. So I implemented methods
Doa interface
public interface DepartmentDao extends JpaRepository<Department, Integer>{
}
I'm stuck how to implement Dao implementation, I used like this
Dao Implementation
#Repository
public class DepartmentDaoImpl implements DepartmentDao {
#Autowired
private SessionFactory sessionFactory;
// All other overridden methods
#Override
public <S extends Department> S save(S entity) {
return (S) sessionFactory.getCurrentSession().save(entity);
}
}
Service interface
public interface DepartmentService {
// Other all necessary methods
public <S extends Department> S save(S entity);
}
Service Implementation
#Service
public class DepartmentServiceImpl implements DepartmentService{
#Autowired
DepartmentDao departmentDao;
#Override
#Transactional
public <S extends Department> S save(S entity) {
return departmentDao.save(entity);
}
}
Controller class
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveDepartment(#Valid #ModelAttribute("departmentForm") Department department) {
departmentService.save(department); //departmen already autowired
return new ModelAndView("redirect:/department/list");
}
I tried to save this object in database, but no transaction happened. There were no errors also. Since I'm new to Spring Boot, I confused myself how to use jparepository. I developed this by using online reference and spent more time.

Related

How to inject HibernateTemplate in HibernateDaoSupport

I use spring version 5.0.1, hibernate version 5.2.12.
When I call getHibernateTemplate (), I get null
what am I doing wrong?
Dao confif:
#PropertySource(value = {"classpath:hibernate.properties"})
#ComponentScan("ru.bochkarev.hmcs.dao")
#EnableTransactionManagement
#Configuration
public class DaoConfig {
#Autowired
private Environment environment;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(environment.getRequiredProperty("hibernate.connection.driver_class"));
dataSource.setUrl(environment.getRequiredProperty("hibernate.connection.url"));
dataSource.setUsername(environment.getRequiredProperty("hibernate.connection.username"));
dataSource.setPassword(environment.getRequiredProperty("hibernate.connection.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
return properties;
}
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("ru.bochkarev.hmcs.model");
sessionFactory.setHibernateProperties(hibernateProperties());
try {
sessionFactory.afterPropertiesSet();
} catch (IOException e) {
e.printStackTrace();
}
return sessionFactory.getObject();
}
#Bean
public HibernateTransactionManager hibernateTransactionManager(){
return new HibernateTransactionManager(sessionFactory());
}
#Bean
public HibernateTemplate hibernateTemplate() {
return new HibernateTemplate(sessionFactory());
}
}
.................................................................
Implement dao:
#Transactional
#Repository
public class DaoTest extends HibernateDaoSupport {
public void save(TestModel testModel) {
getHibernateTemplate().saveOrUpdate(testModel);
}
}
When I call getHibernateTemplate (), I get null
Try below code for your DAO class and let us know if it works.
#Transactional
#Repository
public class DaoTest {
#Autowired
private HibernateTemplate hibernateTemplate;
public void save(TestModel testModel) {
getHibernateTemplate().saveOrUpdate(testModel);
}
}

Hibernate Transaction Advice in Spring MVC

My project is using Spring MVC4, Hibernate 5. I have configured hibernate transaction with Advice Interceptor, but it does not rollback as I would like. Please help me, what is the problem with my configuration?
All my code is as below:
1. Hibernate config:
#Configuration
#EnableTransactionManagement
public class DataSourceConfiguration {
#Autowired
private Environment env;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(
new String[] {env.getProperty("spring.hibernate.packagesToScan")});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
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();
}
}
Spring Advice Interceptor:
#Aspect
#Configuration
public class TxAdviceInterceptor {
private static final String TX_METHOD_NAME = "*";
#Value(value = "${tx-advice.timeout:-1}")
private Integer txMethodTimeout = -1;
private static final String AOP_POINTCUT_EXPRESSION =
"execution(* com.ptg.service..*.*(..))";
#Autowired
private PlatformTransactionManager transactionManager;
#Bean
public TransactionInterceptor txAdvice() {
MatchAlwaysTransactionAttributeSource source = new MatchAlwaysTransactionAttributeSource();
RuleBasedTransactionAttribute transactionAttribute = new RuleBasedTransactionAttribute();
transactionAttribute.setName(TX_METHOD_NAME);
transactionAttribute.setRollbackRules(
Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
transactionAttribute.setTimeout(txMethodTimeout);
source.setTransactionAttribute(transactionAttribute);
return new TransactionInterceptor(transactionManager, source);
}
#Bean
public Advisor txAdviceAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(AOP_POINTCUT_EXPRESSION);
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
DAO:
#Repository
public abstract class GenericDaoImpl{
#Autowired
private SessionFactory sessionFactory;
#Override
public void S save(S entity) {
sessionFactory.save(entity);
}
}
DaoImpl:
#Repository
public class TagDaoImpl extends GenericDaoImpl{
}
#Repository
public class PostDaoImpl extends GenericDaoImpl{
}
Service:
#Service
public class PostServiceImpl{
#Autowired
private PostDao postDao;
#Autowired
private TagDao tagDao;
public void merge(Post post){
tagDao.save();
postDao.save();
}
}
As code above, I would like if postDao.save is error, tagDao is also rollback.
I have found the problem. My configuration is not wrong.
The problem is "Only unchecked exceptions (that is, subclasses of java.lang.RuntimeException) are rollbacked by default. For the case, a checked exception is thrown, the transaction will be committed".
I have test my code with NullPointerException error, therefore Transaction is not rollbacked.
Refer: https://www.catalysts.cc/wissenswertes/spring-transactional-rollback-on-checked-exceptions/
have you tried #Transactional annotation?

Spring JPA+Hibernate not able to fetch record using findAll() of JPARepository

I have created configuration using below code :
#Configuration
#EnableTransactionManagement
#ComponentScan("Name of package")
#EnableJpaRepositories("Name of package")
public class Config {
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "Name of package";
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("Driver Name");
dataSource.setUrl("Url");
dataSource.setUsername("UserName");
dataSource.setPassword("Password");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN);
entityManagerFactoryBean.setJpaProperties(hibProperties());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, "org.hibernate.dialect.DB2Dialect");
properties.put("hibernate.default_schema","Schema Name");
return properties;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
return new PersistenceExceptionTranslationPostProcessor();
}
}
There is an custom repository interface that implements JPARepository.
I have autowired the custom repository in controller and tried to call findAll().But the method returns 0 although there are 3 records in DB.
I am using spring web for rest service calls.
Entity class is created with #Entity and #Table annotations.It has an embedded key which is annotated using #EmbeddedId annotation.
#Repository
public interface EntityRepository extends JpaRepository<EntityTable, Long> {
#SuppressWarnings("unchecked") EntityTable save(EntityTable entityTable);
}
Entity table is the name of my table mapped with db table.

Cannot autowired beans when separate configuration classes

I have a JavaConfig configurated Spring Batch job. The main job configuration file is CrawlerJobConfiguration. Before now, I have all the configuration (infrastructure, autowired beans, etc) in this class and it works fine. So I decided to separate the job configuration from autowired beans and infracstruture beans configuration and create another 2 configuration classes Beans and MysqlInfrastructureConfiguration.
But now I am having problems to run my job. I'm receiving a NullPointerException when the application try to use autowired fields indicating that the autowired is not working.
I put a breakpoint in the methods that create autowired beans to make sure that they are being called and really are, so I cannot realize what can be the problem.
java.lang.NullPointerException: null
at br.com.alexpfx.supermarket.batch.tasklet.StartCrawlerTasklet.execute(StartCrawlerTasklet.java:27) ~[classes/:na]
at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406) ~[spring-batch-core-3.0.6.RELEASE.jar:3.0.6.RELEASE]
Main job configuration class:
#Configuration
#EnableBatchProcessing
public class CrawlerJobConfiguration {
#Autowired
private InfrastructureConfiguration infrastructureConfiguration;
#Autowired
private StepBuilderFactory steps;
#Autowired
Environment environment;
#Bean
public Job job(JobBuilderFactory jobs) {
Job theJob = jobs.get("job").start(crawlerStep()).next(processProductStep()).build();
((AbstractJob) theJob).setRestartable(true);
return theJob;
}
#Bean
public Step crawlerStep() {
TaskletStep crawlerStep = steps.get("crawlerStep").tasklet(crawlerTasklet()).build();
crawlerStep.setAllowStartIfComplete(true);
return crawlerStep;
}
#Bean
public Step processProductStep() {
TaskletStep processProductStep = steps.get("processProductStep")
.<TransferObject, Product>chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
processProductStep.setAllowStartIfComplete(true);
return processProductStep;
}
private Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}
private ItemProcessor<TransferObject, Product> processor() {
return new ProductProcessor();
}
private ItemReader<TransferObject> reader() {
return new ProductItemReader();
}
private ItemWriter<Product> writer() {
return new HibernateProductsItemWriter();
}
}
Beans configuration class:
#Configuration
#EnableBatchProcessing
public class Beans {
#Bean
public Crawler crawler() {
return new RibeiraoCrawler(new UserAgentFactory());
}
#Bean
public ProductBo productBo() {
return new ProductBoImpl();
}
#Bean
public ProductDao productDao() {
return new ProductDaoImpl();
}
#Bean
public CrawlerListener listener() {
CrawlerListener listener = new RibeiraoListener();
return listener;
}
#Bean
public ProductList getProductList() {
return new ProductList();
}
}
MysqlInfrastructureConfiguration:
#Configuration
#EnableBatchProcessing
#PropertySource("classpath:database.properties")
#EnableJpaRepositories(basePackages = {"br.com.alexpfx.supermarket.domain"})
public class MysqlInfrastructureConfiguration implements InfrastructureConfiguration {
#Value("${jdbc.url}")
String url;
#Value("${jdbc.driverClassName}")
String driverClassName;
#Value("${jdbc.username}")
String username;
#Value("${jdbc.password}")
String password;
#Bean
#Override
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
#Override
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
transactionManager.setDataSource(getDataSource());
return transactionManager;
}
#Bean
#Override
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(getDataSource());
em.setPackagesToScan(new String[]{"br.com.alexpfx.supermarket.domain"});
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalJpaProperties());
em.afterPropertiesSet();
return em.getObject();
}
private Properties additionalJpaProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "create");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("current_session_context_class", "thread");
return properties;
}
}
tasklet:
public class StartCrawlerTasklet implements Tasklet {
#Autowired
private Crawler crawler;
#Autowired
private CrawlerListener listener;
#Override
public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
crawler.setListener(listener);
crawler.setStopCondition(new TimeLimitStopCondition(1, TimeUnit.MINUTES));
crawler.crawl();
return RepeatStatus.FINISHED;
}
}
StartCrawlerTasklet use the autowired annotation, so it should be a bean as well. So change your code :
private Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}
to a bean definition:
#Bean
public Tasklet crawlerTasklet() {
return new StartCrawlerTasklet();
}

Spring Data - no transaction is in progress

I'm trying to configure a custom Spring Data Repository to replace some funcionality of spring.
Everything works fine in #Repository interfaces, but in the #Repository implementations, I got no transaction.
Error:
javax.persistence.TransactionRequiredException: no transaction is in progress
Here is my Configuration File:
#Configuration
#ComponentScan ({"com.app.core.authentication", "com.app.core.service","com.app.core.repository"})
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.app.core.repository"})
public class AppCoreConfiguration implements TransactionManagementConfigurer {
#Bean
public DataSource dataSource() {
DataSource dataSource = null;
try {
Context ctx = new InitialContext();
dataSource = (DataSource) ctx.lookup("java:jboss/postgresDS");
} catch (NamingException e) {
e.printStackTrace();
}
return dataSource;
}
#Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.app.core.entity");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
txManager.setDataSource(dataSource());
return txManager;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator(){
return new HibernateExceptionTranslator();
}
#Bean
public EntityManager entityManger () {
return entityManagerFactory().createEntityManager();
}
#Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return transactionManager();
}
}
And my repository class:
#Repository
public class ClientRepository extends JPABaseRepository<String, Client> implements IClientRepository {
#Autowired
public ClienteRepository (EntityManager em) {
super(Cliente.class, em);
}
#Override
#Transactional
public Cliente save(Client client) {
return saveAndFlush(client);
}
}
And the interface:
#NoRepositoryBean
public interface IClientRepository extends IJPABaseRepository<String, Client> {
...
}
Did someone know why this custom #Repository class didn't get the transaction manager?
This is strange, because all interfaces not implemented works fine...
I already tried to put #Transaction's annotation everywhere... including change from RESOURCE_LOCAL to JTA and so on...
When using custom JPA Repositories which extend Spring Data JPA you need a factory to create instances of those repositories. As mentioned in the Spring Data JPA documentation.
The problem with your current approach is the fact that you are creating a, non-spring-managed, instance of an EntityManager.
#Bean
public EntityManager entityManger () {
return entityManagerFactory().createEntityManager();
}
Normally Spring creates a transaction aware proxy for the EntityManager but in your case (due to the #Bean method) your custom implementation gets a plain EntityManager. Creating a factory (as mentioned above) will solve this.

Resources