Hibernate using fully JavaConfig aproach in a Spring Batch Job - spring

I have a batch job fully configured using JavaConfig. having difficulties, mainly due to little material I found on configuration using only java. In the spring batch manual itself there is no information on how to fully configure a job with spring batch using only java. I do not know if it's because this configuration model is more recent than the xml based aprouch...
Right now I'm having trouble setting up hibernate using this configuration class. I have an xml settings, but I'm not knowing how to reference it or how to change these settings for a fully "JavaConfig" version.
My job configuration class is:
#Configuration
#EnableBatchProcessing
public class CrawlerBatchConfiguration {
#Autowired
private StepBuilderFactory steps;
#Bean
public Job job(JobBuilderFactory jobs) {
return jobs.get("myJob").start(flow()).end().build();
}
protected Step step0() {
return steps.get("setupCrawlerStep").tasklet(tasklet()).build();
}
private Flow flow() {
FlowBuilder<Flow> builder = new FlowBuilder<>("flow1");
builder.start(step0())
.next(step1())
.end();
return builder.build();
}
#Bean
protected Step step1() {
return steps.get("processProductStep")
.<TransferObject, Product>chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
#Bean
protected Tasklet tasklet() {
return new StartCrawlerTasklet();
}
#Bean
protected ProductList getProductList() {
return new ProductList();
}
#Bean
public CrawlerListener listener() {
CrawlerListener listener = new RibeiraoListener();
return listener;
}
#Bean
public ItemProcessor<TransferObject, Product> processor() {
return new ProductProcessor();
}
#Bean
public ItemReader<TransferObject> reader() {
return new ProductItemReader();
}
#Bean
public ItemWriter<Product> writer() {
return new HIbernateProductsItemWriter();
}
#Bean
public Crawler crawler() {
return new RibeiraoCrawler(new UserAgentFactory());
}
#Bean
public ProductBo productBo() {
return new ProductBoImpl();
}
#Bean
public ProductDao productDao() {
return new ProductDaoImpl();
}
}
And the hibernate config file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<!-- Hibernate session factory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hbm2ddl.auto">update</prop>
<prop key="current_session_context_class">thread</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>br.com.alexpfx.supermarket.domain.Product</value>
<value>br.com.alexpfx.supermarket.domain.Manufacturer</value>
</list>
</property>
</bean>
</beans>

Related

Bean Required for Spring MVC xml file for Amazon S3

What should be the beans in xml file for this same java based configuration?
#Configuration
#ComponentScan(basePackageClasses = Application.class, excludeFilters = #Filter({Controller.class, Configuration.class}))
public class ApplicationConfig {
#Value("${aws_access_key_id}")
private String awsId;
#Value("${aws_secret_access_key}")
private String awsKey;
#Bean
public static PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocations(new Resource[] {
new ClassPathResource("/amazon.properties")
});
return ppc;
}
#Bean
public AWSCredentials credential() {
return new BasicAWSCredentials(awsId, awsKey);
}
#Bean
public AmazonS3 s3client() {
return new AmazonS3Client(credential());
}
}
<context:property-placeholder
ignore-resource-not-found="true" ignore-unresolvable="true"
system-properties-mode="OVERRIDE" order="0"
location="classpath:amazon.properties"/>
<bean id="credential" class="com.amazonaws.auth.BasicAWSCredentials">
<constructor-arg name="accessKey" value="${aws_access_key_id}"/>
<constructor-arg name="secretKey" value="${aws_secret_access_key}"/>
</bean>
<bean id="s3client" class="com.amazonaws.services.s3.AmazonS3Client">
<constructor-arg ref="credential"/>
</bean>

#Transactional on service layer not rolling back Spring MVC+Hibernate

I have 3 classes (UserSrvImpl in service layer, MailDaoImpl and UserDaoImpl in dao (repository) layer). In my service layer (UserSrvImpl), i have a method that calls a method from MailDaoImpl and a method from UserDaoImpl. These 2 dao methods have to save objects in 2 different tables. These 2 tables have a OneToOne relasionship. My problem is when the first insertion succeeds and the second fails, there is no roll back. I'm struggling with this problem since a week. I applied all the solutions that i found in google, but still no success. Can you please give me a help.
Here is my service layer:
#Service
public class UserSrvImpl implements IUserSrv {
#Autowired
private IUserDao userDao;
#Autowired
private IMailDao mailDao;
#Override
#Transactional
public boolean create(UserDto userDto) {
boolean result = false;
try {
User userToSave = transformDtoToEntity(userDto);
MailToken mailToken = createMailTokenForNewUser(userToSave);
userToSave.setMailToken(mailToken);
if (mailDao.createMailToken(mailToken)) {
result = userDao.create(userToSave);
}
} catch (Exception ex) {
}
return result;
}
The service is calling the dao's method mailDao.createMailToken and userDao.create. If the first succeeds and the second fails, there is no roll back on the first table in the database.
Below is the code in MailDao:
#Repository
public class MailDao implements IMailDao {
#Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
#Override
public boolean createMailToken(MailToken mailToken) {
try {
getSession().save(mailToken);
return true;
} catch (HibernateException ex) {
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
Below is the code in UserDaoImpl:
#Repository
public class UserDaoImpl implements IUserDao {
#Autowired
private SessionFactory sessionFactory;
public Session getSession() {
Session sess = this.sessionFactory.getCurrentSession();
if (sess == null) {
sess = this.sessionFactory.openSession();
}
return sess;
}
#Override
public boolean create(User userToSave) {
try {
getSession().save(userToSave);
return true;
} catch (HibernateException ex) {
ex.printStackTrace();
} catch (Exception ex) {
// TODO: handle exception
}
return false;
}
This is my spring configuration:
<bean id="hibernate5AnnotatedSessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<array value-type="java.lang.String">
<value>com.pointsante.dao.domaine</value>
</array>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
Please can you tell me why the #Transactional on the method in the service layer is not working. Thank you.
you should probably use the HibernateTransactionManager instead of DataSourceTransactionManager.
use
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
instead of
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
also check from where the service is called. if you call it from within the service class itself, the proxy which handles the transaction management wont be used.

Convert JMS out bound channel adapter to equavalent Spring Integration DSL in java 1.7

How can I convert <int-jms:outbound-channel-adapter channel="topicChannel" destination="requestQueue"/> to equivalent Spring Integration DSL in java 1.7
Below is the ActiveMQ configuration:
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</bean>
</property>
<property name="sessionCacheSize" value="10"/>
</bean>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue.demo"/>
</bean>
#Bean
public ActiveMQQueue requestQueue() {
return new ActiveMQQueue("queue.demo");
}
etc.
You can configure the sender like this:
#Configuration
#ComponentScan(basePackages = { "com.sample.dispatcher" })
public class DispatcherConfig {
public static final String JOB_TOPIC = "jobTopic";
#Bean
#ServiceActivator(inputChannel = JOB_TOPIC)
public MessageHandler outboundJmsAdapter(JmsTemplate template) {
JmsSendingMessageHandler handler = new JmsSendingMessageHandler(template);
handler.setDestinationName(JOB_TOPIC);
return handler;
}
#Bean(name = JOB_TOPIC)
public MessageChannel jobTopic() {
return new PublishSubscribeChannel();
}
}
and the listener like this
#Configuration
#ComponentScan(basePackages = { "com.sample.processor" })
#IntegrationComponentScan(basePackages = { "com.sample.processor" })
public class ProcessorConfig {
public static final String ON_POST_JOB = "onPostJob";
public static final String JOB_TOPIC = "jobTopic";
#Bean
public Queue jobTopic() {
return new ActiveMQQueue(JOB_TOPIC);
}
#Bean
public JmsMessageDrivenEndpoint inboundJmsAdapter(ConnectionFactory connectionFactory) {
return new JmsMessageEndpointBuilder()
.setConnectionFactory(connectionFactory)
.setDestination(JOB_TOPIC)
.setInputChannel(onPostJob())
.build();
}
#Bean(name = ON_POST_JOB)
public MessageChannel onPostJob() {
return new PublishSubscribeChannel();
}
}
I have a sample project that uses jms and Spring Integration as form of communication between two applications running on separate vm/process/:
https://github.com/vineey/sample-jobqueue

Mapping hibernate table entities through java configuration

How do we map hibernate table resources when we are configuring through java instead of xml config files - appreciate help.
xml-mapping for hibernate resource:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SybaseDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>/config/Stock.hbm.xml</value>
</list>
</property>
</bean>
Java-mapping?
#Configuration
#EnableTransactionManagement
#PropertySource({ "classpath:persistence-sql.properties" })
#ComponentScan({......."})
public class PersistenceConfig {
#Autowired
private Environment env;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] {...... });
sessionFactory.setHibernateProperties(hibernateProperties());
(HOW DO WE INTRODUCE mappingResources HERE?)
return sessionFactory;
}
The #Entity on the model object solved the problem.
The xml configuration option had not needed this annotation.
you can edit your configuration at runtime like this:
Configuration cfg = new Configuration()
.addResource("Item.hbm.xml")
.addResource("Bid.hbm.xml");
or for class like this:
Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class);
reference here
Here is the minimal working Hibernate+JPA setup you are interested in:
#Configuration
#EnableTransactionManagement
public class DaoConfiguration {
#Bean
public Properties hibernateProperties() {
Properties properties = new Properties();
properties.setProperty(Environment.DIALECT, "org.hibernate.dialect.HSQLDialect");
properties.setProperty(Environment.DRIVER, "org.hsqldb.jdbcDriver");
properties.setProperty(Environment.URL, "jdbc:hsqldb:mem:testdb");
properties.setProperty(Environment.USER, "sa");
properties.setProperty(Environment.PASS, "");
properties.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS, "org.springframework.orm.hibernate4.SpringSessionContext");
properties.setProperty(Environment.STATEMENT_BATCH_SIZE, "30");
properties.setProperty(Environment.SHOW_SQL, "true");
properties.setProperty(Environment.HBM2DDL_AUTO, "update");
return properties;
}
#Bean
public HibernateEntityManagerFactory entityManagerFactory() {
Ejb3Configuration config = new Ejb3Configuration();
return (HibernateEntityManagerFactory) config.addProperties(hibernateProperties()).
addAnnotatedClass(User.class).
buildEntityManagerFactory();
}
#Bean
public SessionFactory sessionFactory() {
return entityManagerFactory().getSessionFactory();
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}

Hibernate SessionFactory vs Spring LocalSessionFactoryBean

I am trying to move a spring3.2.x + hibernate4.x setup from a xml to java configuration.
Heres a snippet of the existing code:
import org.hibernate.SessionFactory;
import org.hibernate.Query;
import org.hibernate.Session;
public class StockDaoImpl implements StockDao{
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(Stock stock){
Session session = getSessionFactory().openSession();
try{
session.save(stock);
}
finally{
session.close();
}
}
The spring config file
<!-- Stock Data Access Object -->
<bean id="stockDao" class="com.data.dao.StockDaoImpl" >
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="dataSource">
.....
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
......
</property>
<property name="mappingResources">
.......
</property>
</bean>
This works fine - but how do i re-define this config in java?
Heres an attempt -
#Bean
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory());
return dao;
}
......
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { .....});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
But this wont compile as the sessionFactory being referred to is not Spring's LocalSessionFactoryBean?
How do I reconcile this?
LocalSessionFactoryBean is a FactoryBean<SessionFactory>. It means that it allows creating instances of SessionFactory.
So you just need
public StockDao stockDao() {
StockDaoImpl dao=new StockDaoImpl();
dao.setSessionFactory(sessionFactory().getObject());
return dao;
}
But I wouldn't create DAOs explicitel like that. Simply annotate your DAO with #Repository, and autowire the session factory using #Autowired. Make sure the Java config class is annotated with #ComponentScan("the.base.package.of.daos")
Missing getObject() call in return.
Substituite with return sessionFactory.getObject() (and change return type,too!)
JB Nizet's answer helped me, but I needed to declare the beans separately for it to work:
#Bean
public LocalSessionFactoryBean sessionFactoryBean(final DataSource dataSource,
final Properties hibernateProperties,
final List<String> hibernateMappings) {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
sessionFactoryBean.setMappingResources(hibernateMappings.toArray(new String[hibernateMappings.size()]));
return sessionFactoryBean;
}
#Bean
public SessionFactory sessionFactory(LocalSessionFactoryBean sessionFactoryBean) {
return sessionFactoryBean.getObject();
}

Resources