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
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);
}
}
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?
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.
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();
}
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.