I am using Spring AOP for logging in my application. Here is the applicationContext.xml file
<mvc:annotation-driven />
<context:component-scan base-package="com.template" />
<context:annotation-config />
<jpa:repositories base-package="com.template.repository"/>
<tx:annotation-driven />
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/template?autoReconnect=true"/>
<property name="username" value="root"/>
<property name="password" value=""/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitName" value="template"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
and my aopLogging.xml is
<bean id="aopLogging" class="com.template.log.AopLoggingAspect" />
<aop:aspectj-autoproxy proxy-target-class="false"/>
and my Aspect class is
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
#Aspect
#Component
public class AopLoggingAspect {
private static final Logger logger = Logger.getLogger(AopLoggingAspect.class);
#Around(value="#annotation(com.template.log.Loggable)")
public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable{
Object retVal = null;
try {
StringBuffer startMessageStringBuffer = new StringBuffer();
startMessageStringBuffer.append("Start method execution :: ");
startMessageStringBuffer.append(joinPoint.getSignature().getName());
startMessageStringBuffer.append("(");
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
startMessageStringBuffer.append(args[i]).append(",");
}
if (args.length > 0) {
startMessageStringBuffer.deleteCharAt(startMessageStringBuffer.length() - 1);
}
startMessageStringBuffer.append(")");
logger.info(startMessageStringBuffer.toString());
StopWatch stopWatch = new StopWatch();
stopWatch.start();
retVal = joinPoint.proceed();
stopWatch.stop();
StringBuffer endMessageStringBuffer = new StringBuffer();
endMessageStringBuffer.append("Finish method ");
endMessageStringBuffer.append(joinPoint.getSignature().getName());
endMessageStringBuffer.append("(..); execution time: ");
endMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
endMessageStringBuffer.append(" ms;");
logger.info(endMessageStringBuffer.toString());
} catch(Exception ex) {
StringBuffer errorMessageStringBuffer = new StringBuffer();
logger.error(errorMessageStringBuffer.toString(), ex);
throw ex;
}
return retVal;
}
}
and my Custom annotation is
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface Loggable {
}
and my Service class is
public class UserService {
#Transactional(readOnly=true)
#Loggable
public User getUserByUserId(Long userId){
return userRepository.findOne(userId);
}
}
The problem is that the logs are not getting printed. Please help me. Thanks in advance. Please do let me know if any other info is needed.
It seems to me you have forgot to import in your applicationContext.xml file the aopLogging.xml file. Try to add this to your applicationContext.xml file:
<!-- Import your AspectJ config -->
<import resource="classpath:aopLogging.xml" />
Create a Annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface LogExecutionTime { }
Then an Aspect
#Aspect
#Component
public class LoggingAspect {
Then a method in the Aspect
#Around("#annotation(LogExecutionTime)")
public Object
logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object proceed = joinPoint.proceed();
long executionTime = System.currentTimeMillis() - start;
LOGGER.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return proceed; }
Then use the Annotation Anywhere
#PostMapping(value="/signup")
#LogExecutionTime
public #ResponseBody
ResponseObject register(User user){
}
Try this..
#Around(value="#annotation(Loggable)")
public Object logAround(final ProceedingJoinPoint joinPoint) throws Throwable{
Related
I have implemented transactional rollback in the following way. This code worked well when I tried to implement the same on HSql DB and SQL Server. But the same transactional rollback is not working when implemented on MySQL DB. What could be the possible solution for rolling back the transaction in case of MySQL?
Here is my code -
xml file-> implement.xml
<?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-3.0.xsd ">
<!-- Initialization for data source -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://(mydb details)"/>
<property name="username" value="(my db username)"/>
<property name="password" value="(my db password)"/>
</bean>
<!-- Initialization for TransactionManager -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- Definition for studentJDBCTemplate bean -->
<bean id="implementOnlyTransactions" class="Transactions.implementOnlyTransactions">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
</bean>
</beans>
implementOnlyTransactions.java->
package Transactions;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
public class implementOnlyTransactions {
private DataSource dataSource;
private JdbcTemplate jdbcTemplateObject;
private PlatformTransactionManager transactionManager;
public void setDataSource(DataSource dataSource) throws SQLException {
this.dataSource = dataSource;
this.jdbcTemplateObject = new JdbcTemplate(dataSource);
}
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public void create(Integer id, String name) throws Exception {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
String SQL1 = "insert into Student (ID,Name) values (?, ?)";
int r = jdbcTemplateObject.update(SQL1, id, name);
System.out.println("Inserted Name = " + name + ", ID = " + id);
if(r>0){
transactionManager.rollback(status);
}
transactionManager.commit(status);
} catch (DataAccessException e) {
System.out.println("Error in creating record, rolling back");
//transactionManager.rollback(status);
throw e;
}
}
}
MainClass.java -->
package Transactions;
import java.sql.SQLException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainClass {
public static void main(String[] args) throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("xmlFiles/implement.xml");
implementOnlyTransactions implemt =
(implementOnlyTransactions)context.getBean("implementOnlyTransactions");
try {
implemt.create(36,"bye2");
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
i am importing data from file ,its get the data suceessfully .my flow to call the ruleimplservice from the main class ,where i get the value from file.bt when i call jdbclogdatarepository to save the data ,it shows the following error.the data isreached successfully in impl bt not in jdbc class.
ERRORS
java.lang.NullPointerException
at com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl.insertlogcontent(RuleServiceImpl.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at $Proxy6.insertlogcontent(Unknown Source)
at com.heavymeddlellc.heavymeddle.utils.readingdata.main(readingdata.java:97)
Java code is as below:
package com.heavymeddlellc.heavymeddle.utils;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.test.context.ContextConfiguration;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.jdbc.JdbcLogDataRepository;
import com.heavymeddlellc.heavymeddle.metrics.service.RuleService;
import com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl;
#ContextConfiguration(locations = "/hm-metrics-context.xml")
public class readingdata
{
public static void main(String args[])
{
//RuleService ruleService=new RuleService();
List<LogData> dataList = new ArrayList<LogData>();
Resource r= new ClassPathResource("/hm-metrics-context.xml");
BeanFactory factory=new XmlBeanFactory((org.springframework.core.io.Resource) r);
// LogData logData=(LogData) factory.getBean("ruleService");
RuleService ruleService=(RuleService) factory.getBean("ruleService");
// JdbcLogDataRepository dataRepository= (JdbcLogDataRepository) factory.getBean("ruleService");
LogData logData=new LogData();
// public List<LogData> inserttable(LogData logData2)
//{
try
{
BufferedReader reader=new BufferedReader(new FileReader("E://tracker.log"));
String lines;
String[] contentid;
while((lines=reader.readLine())!=null)
{
String[] datas=lines.split(Pattern.quote("|"));
logData.setUserId(datas[0]);
logData.setRequestDate(datas[1]);
System.out.println(datas[1]);
logData.setSessionId(datas[2]);
System.out.println(datas[2]);
// System.out.println(datas[2]);
contentid=datas[2].split("html/meta/content/");
// System.out.println(contentid[0]);
// System.out.println(datas[2]);
logData.setContentId(contentid[0]);
System.out.println(contentid[0]);
logData.setUserAgent(datas[6]);
System.out.println(datas[6]);
logData.setUserType(datas[4]);
logData.setReferer(datas[5]);
logData.setRedirectUrl(datas[7]);
String sessionId=logData.getSessionId();
System.out.println(logData.getSessionId());
String contentId=logData.getContentId();
System.out.println(contentId);
String userAgent=logData.getUserAgent();
System.out.println(userAgent);
String requestDate=logData.getRequestDate();
String userId=logData.getUserId();
String userType=logData.getUserType();
String referer=logData.getReferer();
String redirectUrl=logData.getRedirectUrl();
//Saystem.out.println(datas[4]);
// dataList.add(logData);
// System.out.print(logData.getSessionId());
//ruleService.insertlogcontent(logData.setSessionId(datas[2]),logData.setContentId(contentid[0]), logData.setRequestDate(datas[1]), logData.setUserId(datas[0]),logData.setUserType(datas[4]),logData.setReferer(datas[5]),logData.setRedirectUrl(datas[7]));
ruleService.insertlogcontent(sessionId, contentId, userAgent, requestDate, userId, userType, referer, redirectUrl);
}
}
catch(Exception e)
{
e.printStackTrace();
}
// return dataList;
// }
}}
/**
*
*/
ruleServiceimpls
package com.heavymeddlellc.heavymeddle.metrics.service;
import java.util.List;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.*;
import org.springframework.transaction.annotation.Transactional;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.LogDataRepository;
#Repository
public class RuleServiceImpl implements RuleService {
private static final Logger log = Logger.getLogger(RuleServiceImpl.class);
#Autowired
private LogDataRepository logDataRepository;
#Override
public void insertlogcontent(String sessionId, String contentId, String userAgent,
String requestDate, String userId,
String userType, String referer,
String redirectUrl) {
//logDataRepository.insertlogcontent(sessionId, contentId,userAgent, requestDate, userId, userType, referer, redirectUrl);
System.out.println(sessionId);
System.out.println(requestDate);
System.out.println(userType);
logDataRepository.insertlogcontent(sessionId, contentId, userAgent,
requestDate, userId, userType, referer, redirectUrl);
}
}
/**
*
*/
package com.heavymeddlellc.heavymeddle.metrics.repository.jdbc;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.heavymeddlellc.heavymeddle.metrics.MetricsException;
import com.heavymeddlellc.heavymeddle.metrics.domain.LogData;
import com.heavymeddlellc.heavymeddle.metrics.repository.LogDataRepository;
import com.heavymeddlellc.heavymeddle.utils.readingdata;
#Transactional
#Repository("logDataRepository")
public class JdbcLogDataRepository implements LogDataRepository {
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private final static String LOG_REDIRECT_VIEW_TABLENAME = "hm_log_redirect_view";
private final static String LOG_REDIRECT_URL_LOOKUP_TABLENAME = "hm_log_redirect_url_lookup";
public final static String LOG_ALL_CONTENTS_VIEW_TABLENAME = "hm_log_all_contents_view";
private final static String LOG_ALL_SN_CONTENTS_VIEW = "hm_log_sn_contents_view";
#Override
public void insertlogcontent(String sessionId, String contentId, String userAgent,
String requestDate, String userId,
String userType, String referer,
String redirectUrl) {
int values=0;
System.out.println(userType);
StringBuffer sqlQuery = new StringBuffer(
"insert into "+JdbcLogDataRepository.LOG_ALL_CONTENTS_VIEW_TABLENAME
+"(uri,content_id,content_owner_id,request_date,user_id,user_type,referer,redirect_url) values (?,?,?,?,?,?,?,?)");
values=jdbcTemplate.update(sqlQuery.toString(),sessionId,contentId,userAgent,requestDate,userId,userType,referer,redirectUrl);
}
}
Spring xml
<!-- Activates scanning of #Autowired -->
<context:annotation-config />
<context:component-scan base-package="com.heavymeddlellc.heavymeddle.metrics" />
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (this dependency is defined somewhere else) -->
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="metricsProcessor" class="com.heavymeddlellc.heavymeddle.metrics.processor.MetricsProcessorImpl">
<constructor-arg ref="taskExecutor" />
<property name="ruleService" ref="ruleService"/>
</bean>
<bean id="ruleService" scope="prototype" class="com.heavymeddlellc.heavymeddle.metrics.service.RuleServiceImpl">
<!-- This instructs the container to proxy the current bean-->
<aop:scoped-proxy proxy-target-class="false"/>
</bean>
<!-- <bean id="logDataRepository" scope="prototype" class="com.heavymeddlellc.heavymeddle.metrics.repository.JdbcLogDataRepository">
This instructs the container to proxy the current bean
<aop:scoped-proxy proxy-target-class="false"/>
<property name="ruleService" ref="ruleService"></property>
</bean>
-->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="50" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="150" />
</bean>
</beans>
Replace the following two lines:
Resource r = new ClassPathResource("/hm-metrics-context.xml");
BeanFactory factory = new XmlBeanFactory((org.springframework.core.io.Resource) r);
with this:
ApplicationContext factory = new ClassPathXmlApplicationContext("/hm-metrics-context.xml");
Read this section of the reference documentation about the differences between a BeanFactory and an ApplicationContext.
Your auto-wiring doesn't work because <context:annotation-config/> is processed as a BeanPostProcessor and the BeanFactory is missing this feature of using BeanPostProcessor extension points, as per the link from the docs above.
I want to create a batch using Spring batch to read from an ini file and save the data in database but when I chekced the org.springframework.batch.item.file.FlatFileItemReader class I didn't find a way to parse my data from the ini file , I tried to combine the ini4j API with the spring batch but no result
my ini file :
[Cat]
a=1
b= 2
c= 3
d= 4
e= 5
f= 6
[Cat2]
a=11
b= 21
c= 31
d= 41
e= 51
f= 61
What you can do is define your own ItemStreamReader that wraps a delegate ItemStreamReader, which is just a FlatFileItemReader that uses a PatternMatchingCompositeLineMapper as the line mapper. In your ItemStreamReader, loop to read lines from your delegate and if the line is an instance of a Property domain object then add it to a list in a Section domain object. What the PatternMatchingCompositeLineMapper allows you do do is check the line for a pattern match, and pass it to the right tokenizer and fieldSetMapper for the job.
Doing it this way will allow you to read multiple lines into one Section domain object that holds a List<Property>.
public class Section {
private String name;
private List<Property> properties;
// getters and setters
#Override
public String toString() {
StringBuilder sb = new StringBuilder(name);
for (Property prop: properties) {
sb.append("," + prop.getKey() + "=" + prop.getValue());
}
return sb.toString();
}
}
public class Property {
private String key;
private String value;
// getters and setters
}
For you custom ItemStreamReader you would do this. You can see that the reading is delegated to another reader, which you will define later
import java.util.ArrayList;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.ItemStreamReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
public class IniFileItemReader implements ItemStreamReader<Object> {
private Object curItem = null;
private ItemStreamReader<Object> delegate;
#Override
public Object read() throws Exception, UnexpectedInputException,
ParseException, NonTransientResourceException {
if (curItem == null) {
curItem = (Section) delegate.read();
}
Section section = (Section) curItem;
curItem = null;
if (section != null) {
section.setProperties(new ArrayList<Property>());
while (peek() instanceof Property) {
section.getProperties().add((Property) curItem);
curItem = null;
}
}
return section;
}
private Object peek() throws Exception {
if (curItem == null) {
curItem = delegate.read();
}
return curItem;
}
public void setDelegate(ItemStreamReader<Object> delegate) {
this.delegate = delegate;
}
#Override
public void close() throws ItemStreamException {
delegate.close();
}
#Override
public void open(ExecutionContext arg0) throws ItemStreamException {
delegate.open(arg0);
}
#Override
public void update(ExecutionContext arg0) throws ItemStreamException {
delegate.update(arg0);
}
}
Then in your config you define the deleagte reader with the PatternMatchingCompositeLineMapper
<bean id="inputFile" class="org.springframework.core.io.FileSystemResource"
scope="step">
<constructor-arg value="#{jobParameters[inputFile]}"></constructor-arg>
</bean>
<bean id="sectionFileReader"
class="com.underdogdevs.springbatch.reader.IniFileItemReader">
<property name="delegate" ref="trueSectionFileReader"></property>
</bean>
<bean id="trueSectionFileReader"
class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="lineMapper">
<bean
class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper">
<property name="tokenizers">
<map>
<entry key="[*" value-ref="sectionLineTokenizer">
</entry>
<entry key="*" value-ref="propertyLineTokenizer"></entry>
</map>
</property>
<property name="fieldSetMappers">
<map>
<entry key="[*" value-ref="sectionFieldSetMapper">
</entry>
<entry key="*" value-ref="propertyFieldSetMapper">
</entry>
</map>
</property>
</bean>
</property>
<property name="resource" ref="inputFile"></property>
</bean>
<bean id="sectionLineTokenizer"
class="com.underdogdevs.springbatch.tokenizer.SectionLineTokenizer">
</bean>
<bean id="sectionFieldSetMapper"
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="section"></property>
</bean>
<bean id="section" class="com.underdogdevs.springbatch.domain.Section"
scope="prototype">
</bean>
<bean id="propertyLineTokenizer"
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="delimiter" value="="></property>
<property name="names" value="key,value"></property>
</bean>
<bean id="propertyFieldSetMapper"
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<property name="prototypeBeanName" value="property"></property>
</bean>
<bean id="property" class="com.underdogdevs.springbatch.domain.Property"
scope="prototype">
</bean>
You see that I also used a custom LineTozenizer. I probably could've just used a DelimitedLineTokenizer, but by the time I realized it, I had already defined the class
import org.springframework.batch.item.file.transform.DefaultFieldSetFactory;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.batch.item.file.transform.FieldSetFactory;
import org.springframework.batch.item.file.transform.LineTokenizer;
public class SectionLineTokenizer implements LineTokenizer {
private final String nameField = "name";
private final FieldSetFactory fieldSetFactory = new DefaultFieldSetFactory();
#Override
public FieldSet tokenize(String line) {
String name = line.replaceAll("\\[", "").replaceAll("\\]", "").trim();
return fieldSetFactory.create(new String[] { name },
new String[] { nameField });
}
}
Using the following writer and job
<bean id="outputFile"
class="org.springframework.core.io.FileSystemResource" scope="step">
<constructor-arg value="#{jobParameters[outputFile]}"></constructor-arg>
</bean>
<bean id="outputFileWriter"
class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" ref="outputFile"></property>
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.PassThroughLineAggregator">
</bean>
</property>
</bean>
<batch:step id="outputStep">
<batch:tasklet>
<batch:chunk commit-interval="10" reader="sectionFileReader"
writer="outputFileWriter">
<batch:streams>
<batch:stream ref="sectionFileReader" />
<batch:stream ref="trueSectionFileReader" />
</batch:streams>
</batch:chunk>
</batch:tasklet>
</batch:step>
<batch:job id="iniJob">
<batch:step id="step1" parent="outputStep"></batch:step>
</batch:job>
And using this ini file
[Cat]
a=1
b=2
c=3
d=4
e=5
f=6
[Cat2]
a=11
b=21
c=31
d=41
e=51
f=61
I get the following output, which is the format in my toString() of the Section class
Cat,a=1,b=2,c=3,d=4,e=5,f=6
Cat2,a=11,b=21,c=31,d=41,e=51,f=61
Here's the error I'm receiving.
Caused by: java.lang.IllegalStateException: Cannot convert value of type [code.ProductFieldSetMapper] to required type [org.springframework.batch.item.file.mapping.FieldSetMapper] for property 'FieldSetMapper': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:450)
... 23 more
Here's my context file (FileReaderConfig.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch="http://www.springframework.org/schema/batch"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd">
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader">
<property name="resource" value="file:./output.txt" />
<property name="linesToSkip" value="1" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="PRODUCT_ID,NAME,DESCRIPTION,PRICE" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="code.ProductFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<job id="importProducts" xmlns="http://www.springframework.org/schema/batch">
<step id="readWriteProducts">
<tasklet>
<chunk reader="reader" writer="writer" commit-interval="100" />
</tasklet>
</step>
</job>
Here's the interface (FieldSetMapper.java)
package code;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public interface FieldSetMapper<T> {
T mapFieldSet(FieldSet fieldSet) throws BindException;
}
Here's ProductFieldSetMapper.java
package code;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class ProductFieldSetMapper implements FieldSetMapper<Product> {
public Product mapFieldSet(FieldSet fieldSet) throws BindException {
// TODO Auto-generated method stub
Product product = new Product();
product.setId(fieldSet.readString("PRODUCT_ID"));
product.setName(fieldSet.readString("NAME"));
product.setDescription(fieldSet.readString("DESCRIPTION"));
product.setPrice(fieldSet.readBigDecimal("PRICE"));
return product;
}
}
And here's the class that I'm running (Runner.java)
package code;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.validation.BindException;
public class Runner {
public static void main(String[] args) throws BeansException, BindException {
// TODO Auto-generated method stub
Product product;
ApplicationContext context =
new ClassPathXmlApplicationContext("FileReaderConfig.xml");
ProductFieldSetMapper obj = (ProductFieldSetMapper) context.getBean("FieldSetMapper");
product = (Product) obj.mapFieldSet((FieldSet)context.getBean("lineTokenizer"));
System.out.println(product.getDescription() + ""+product.getId()+""+product.getName());
}
}
I don't see where (or why for that matter)my code is attempting to convert a ProductFieldSetMapper into a FieldSetMapper (which is just an interface, I understand that won't work).
BTW, Product.java is a POJO with variables and their respective setters and getters.
The error was the result of me using my own interface rather than the one provided by Spring. I deleted my interface class and had ProductFieldSetMapper implement org.springframework.batch.item.file.mapping.FieldSetMapper after importing it. That solved the issue.
ProductFieldSetMapper obj =
(ProductFieldSetMapper) context.getBean("FieldSetMapper");
Should be
ProductFieldSetMapper obj =
(ProductFieldSetMapper) context.getBean("fieldSetMapper");
See your bean declaration.
<property name="fieldSetMapper">
<bean class="code.ProductFieldSetMapper" />
</property>
Here is code with some correction:
Runner.java (use DelimitedLineTokenizer class to tokenize a comma separated string into FieldSet that is further used to map it with an object (Product) via ProductFieldSetMapper class)
ApplicationContext context = new ClassPathXmlApplicationContext(
"FileReaderConfig.xml");
ProductFieldSetMapper obj = (ProductFieldSetMapper) context.getBean("fieldSetMapper");
DelimitedLineTokenizer tokenizer = (DelimitedLineTokenizer) context
.getBean("lineTokenizer");
FieldSet fieldSet = tokenizer.tokenize("1,Pepsi,Cold drinks,30");
Product product = (Product) obj.mapFieldSet(fieldSet);
System.out.println(product.getDescription() + "-" + product.getId() + "-"
+ product.getName());
Config xml file: (No need to declare any beans or jobs other than two defined below because you are not using it anywhere in you Main class)
<bean id="lineTokenizer"
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="PRODUCT_ID,NAME,DESCRIPTION,PRICE" />
</bean>
<bean id="fieldSetMapper" class="com.spring.batch.domain.ProductFieldSetMapper" />
ProductFieldSetMapper.java: (There is no need to define your custom FieldSetMapper)
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class ProductFieldSetMapper implements org.springframework.batch.item.file.mapping.FieldSetMapper<Product> {
public Product mapFieldSet(FieldSet fieldSet) throws BindException {
Product product = new Product();
product.setId(fieldSet.readString("PRODUCT_ID"));
product.setName(fieldSet.readString("NAME"));
product.setDescription(fieldSet.readString("DESCRIPTION"));
product.setPrice(fieldSet.readBigDecimal("PRICE"));
return product;
}
}
For a detailed sample please read it HERE with extra functionality using spring batch jobs.
All. Attached herewith all the files. If I give the same name for both bean property name and reference, it returns the object. But it returns null, in case both are different. Please help. Thank you so much.
The AuthenticateAction.java file has got the detailed comments inside it.....
below are my files list:
WIRAdminBaseAction.java ---> my base action
AuthenticateAction.java ---> my java file that calls the bean here
applicationContext_MNC.xml
The below way of calling works...... This is not encouraged, as we
should not use applicationContext always
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletRequest().getSession().getServletConte xt());
ICacheDelegate cacheAction = (ICacheDelegate)applicationContext.getBean("BMOCacheDelegate");
The below way of calling does NOT work .... returns null value....
Please help... I assume that, since I have extended the
WIRAdminBaseAction, i should be able to call the getCacheDelegate
directly and it should return my cacheDelegate object ... Again,
Please note.....if I change my applicationContext_MNC.xml as below,
the below way of calling works fine. But, i don't want to change my
applicationContext_MNC.xml as below, due to some necessity.
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
<bean id="cacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
Is it that the name and bean should have the same value.... ??? No
Need to be.....Am i right ? Please advise.
getCacheDelegate().getActorAction(1); // this way of calling doesn't work and returns null value. please help.
MY CODE Follows below.
AuthenticateAction.java
package com.symcor.wiradmin.web.action;
import java.net.UnknownHostException;
import java.sql.SQLException;
import org.bouncycastle.crypto.CryptoException;
import org.springframework.context.ApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.web.context.support.WebApplica tionContextUtils;
import com.symcor.wiradmin.delegate.ICacheDelegate;
public class AuthenticateAction extends WIRAdminBaseAction {
private static final long serialVersionUID = 1L;
public String authenticate() throws UnknownHostException, CryptoException,
DataAccessException, SQLException{
/** This way of calling works...... This is not encouraged, as we should not use applicationContext always **/
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContex t(getServletRequest().getSession().getServletConte xt());
ICacheDelegate cacheAction = (ICacheDelegate) applicationContext.getBean("BMOCacheDelegate");
/** The below way of calling does NOT work .... returns null value.... Please help...
* I assume that, since I have extended the WIRAdminBaseAction, i should be able to call the getCacheDelegate directly
* and it should return my cacheDelegate object ...
* Again, Please note.....if I change my applicationContext_MNC.xml as below, the below way of calling works fine...
* but, i don't want to change my applicationContext_MNC.xml as below, due to some necessity.
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="cacheDelegate" />
</property>
</bean>
<bean id="cacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
... is it that the name and bean should have the same value.... ??? No Need to be.....Am i right ? Please advise.
*
* **/
getCacheDelegate().getActorAction(1); // this way of calling doesn't work and returns null value. please help.
return "success";
}
}
WIRAdminBaseAction.java
package com.symcor.wiradmin.web.action;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.interceptor.ParameterAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.config.entities.Parameteri zable;
import com.symcor.wiradmin.delegate.ICacheDelegate;
public class WIRAdminBaseAction extends ActionSupport implements Preparable, ParameterAware, Parameterizable, SessionAware,RequestAware {
private HttpServletRequest request;
private static final long serialVersionUID = 1L;
private HttpServletResponse response;
private ICacheDelegate cacheDelegate;
private Map session;
private Map<String, String> params;
private Map parameters;
public void prepare() throws Exception {
}
public String execute() throws Exception {
return SUCCESS;
}
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletRequest getServletRequest() {
return this.request;
}
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
public HttpServletResponse getServletResponse() {
return this.response;
}
public ICacheDelegate getCacheDelegate() {
return cacheDelegate;
}
public void setCacheDelegate(ICacheDelegate cacheDelegate) {
this.cacheDelegate = cacheDelegate;
}
public void addParam(final String key, final String value) {
this.params.put(key, value);
}
public Map getParams() {
return params;
}
public void setParams(final Map<String, String> params) {
this.params = params;
}
public Map getSession() {
return this.session;
}
public void setSession(final Map session) {
this.session = session;
}
public void setParameters(final Map param) {
this.parameters = param;
}
}
applicationContext_MNC.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- database configuration from property file -->
<bean id="BMOAdminDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" lazy-init="default" autowire="default" dependency-check="default">
<property name="driverClass" value="${jdbc.driver}" ></property>
<property name="jdbcUrl" value="${admin.jdbc.url}" ></property>
<property name="user" value="${admin.jdbc.user}" ></property>
<property name="password" value="${admin.jdbc.password}" ></property>
<property name="initialPoolSize" value="3" ></property>
<property name="minPoolSize" value="3" ></property>
<property name="maxPoolSize" value="25" ></property>
<property name="acquireIncrement" value="1" ></property>
<property name="acquireRetryDelay" value="1000" ></property>
<property name="debugUnreturnedConnectionStackTraces" value="true" ></property>
<property name="maxIdleTime" value="300" ></property>
<property name="unreturnedConnectionTimeout" value="300000" ></property>
<property name="preferredTestQuery" value="SELECT COUNT(*) FROM LOCALE_CODE" ></property>
<property name="checkoutTimeout" value="300000" ></property>
<property name="idleConnectionTestPeriod" value="600000" ></property>
</bean>
<bean id="BMOWIRAdminBaseAction" class="com.symcor.wiradmin.web.action.WIRAdminBase Action">
<property name="cacheDelegate">
<ref bean="BMOCacheDelegate" />
</property>
</bean>
<bean id="BMOCacheDelegate" class="com.symcor.wiradmin.delegate.CacheDelegate" >
<property name="statusDBDAO"><ref bean="BMOStatusDBDAO" /></property>
</bean>
<bean id="BMOStatusDBDAO" class="com.symcor.wiradmin.dao.StatusDBDAO">
<property name="dataSource">
<ref bean="BMOAdminDataSource" />
</property>
</bean>
<!-- this bean is set to map the constants which needs to be configured as per
the environment to the java constants file -->
<bean id="envConstantsConfigbean" class="com.symcor.wiradmin.util.constants.Environm entConstantsSetter">
<property name="loginUrl" value="${login.url}"/>
<property name="logoutIR" value="${logout.from.image.retrieval}"/>
<property name="adminModuleUrl" value="${admin.url}"/>
<property name="adminUrlSym" value="${admin.url.sym}"/>
<property name="envProperty" value="${env.property}"/>
</bean>
</beans>