0
votes

I'm trying to run my first Batch Spring application but I have thw following issue with the row mapper at runtime:

Cannot convert value of type [com.tutoref.batch.ProductMapper] to required type [org.springframework.jdbc.core.RowMapper] for property 'rowMapper': no matching editors or conversion strategy found

The program must export some data from my sql to flat file (csv). In the following I include the main files (I can add any file if it is required). I'm also concerned with the versions in my pom.xml.

My IDE is eclipse. and here is my pom.xml :

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0         http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.tutoref</groupId>
  <artifactId>spring-batch-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>spring-batch-example</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <!-- Spring core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>
    <!-- Spring batch core -->
    <dependency>
        <groupId>org.springframework.batch</groupId>
        <artifactId>spring-batch-core</artifactId>
        <version>3.0.8.RELEASE</version>
    </dependency>
    <!-- MySQL connector -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.6</version>
    </dependency>
    <!-- Spring jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.10.RELEASE</version>
    </dependency>
    <!-- The JAXB Api -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.6</version>
    </dependency>
    <!-- Junit for unit testing -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

My job definition xml :

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:batch="http://www.springframework.org/schema/batch"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/batch
        http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    ">

    <import resource="spring-context.xml" />
    <import resource="datasource.xml" />

    <bean id="product" class="com.tutoref.batch.entity.Product" scope="prototype" />
    <bean id="itemProcessor" class="com.tutoref.batch.ProductItemProcessor" />
    <bean id="jobListener" class="com.tutoref.batch.ProductJobListener" />


    <!-- Reading from the database and returning a mapper row -->
    <bean id="productItemReader"
        class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="productDataSource" />
        <property name="sql" value="SELECT * FROM products" />
        <property name="rowMapper">
            <bean class="com.tutoref.batch.ProductMapper" />
        </property>

    </bean>

    <!-- Writing a line into an output flat file -->
    <bean id="productFlatFileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
        <property name="resource" value="file:csv/products.csv" />
        <!-- Converting a product object into delimited list of strings -->
        <property name="lineAggregator">
            <bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
                <property name="delimiter" value="|" />
                <property name="fieldExtractor">
                    <!-- Returning the value of beans property using reflection -->
                    <bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
                        <property name="names" value="name,unitPrice,quantity" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <!-- And finally ... the job definition -->
    <batch:job id="productJob">
        <batch:step id="step1">
            <batch:tasklet transaction-manager="transactionManager">
                <batch:chunk reader="productItemReader" writer="productFlatFileItemWriter"
                    processor="itemProcessor" commit-interval="10" />
            </batch:tasklet>
        </batch:step>
        <batch:listeners>
            <batch:listener ref="jobListener" />
        </batch:listeners>
    </batch:job>
</beans>

The row mapper code :

public class ProductMapper implements FieldSetMapper<Product> {

    @Override
    public Product mapFieldSet(FieldSet fieldSet) throws BindException {
        Product product = new Product();
        product.setId(fieldSet.readInt(0));
        product.setName(fieldSet.readString(1));
        product.setQuantity(fieldSet.readInt(2));
        product.setUnitPrice(fieldSet.readDouble(3));
        return product;
    }


}

And the main class :

public class App 
{
    public static void main(String[] args){

        ApplicationContext context = new ClassPathXmlApplicationContext("job-products.xml");

        JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher");
        Job job = (Job) context.getBean("productJob");

        try {
            JobExecution execution = jobLauncher.run(job, new JobParameters());
            System.out.println("Job Exit Status : "+ execution.getStatus());

        } catch (JobExecutionException e) {
            System.out.println("The Job has failed :" + e.getMessage());
            e.printStackTrace();
        }

    }
}

The stack trace of the exception :

INFO: No TaskExecutor has been set, defaulting to synchronous executor. Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. Jul 30, 2017 2:09:59 PM org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName INFO: Loaded JDBC driver: com.mysql.jdbc.Driver Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'productItemReader' defined in class path resource [job-products.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.tutoref.batch.ProductMapper' to required type 'org.springframework.jdbc.core.RowMapper' for property 'rowMapper'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.tutoref.batch.ProductMapper] to required type [org.springframework.jdbc.core.RowMapper] for property 'rowMapper': no matching editors or conversion strategy found at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:703) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:760) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83) at com.tutoref.batch.App.main(App.java:19) Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.tutoref.batch.ProductMapper' to required type 'org.springframework.jdbc.core.RowMapper' for property 'rowMapper'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.tutoref.batch.ProductMapper] to required type [org.springframework.jdbc.core.RowMapper] for property 'rowMapper': no matching editors or conversion strategy found at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:474) at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:511) at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:505) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1502) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1461) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1197) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537) ... 11 more Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.tutoref.batch.ProductMapper] to required type [org.springframework.jdbc.core.RowMapper] for property 'rowMapper': no matching editors or conversion strategy found at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:267) at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:459) ... 17 more

Thanks

1

1 Answers

2
votes

Cannot convert value of type [com.tutoref.batch.ProductMapper] to required type [org.springframework.jdbc.core.RowMapper] for property 'rowMapper': no matching editors or conversion strategy found

This exception means that productItemReader bean is waiting for a org.springframework.jdbc.core.RowMapper object in the rowmapper property, but it's receiving a reference object of type com.tutoref.batch.ProductMapper.

The issue is in public class ProductMapper implements FieldSetMapper<Product>

Go to ProductMapper class and implements org.springframework.jdbc.core.RowMapper instead of FieldSetMapper

This is an example of how implement RowMapper Interface, MessageContainer is a pojo example like Product class in your project.

public class MessageContainerMapper implements RowMapper<MessageContainer> {

    @Override
    public MessageContainer mapRow(ResultSet rs, int rowNum) throws SQLException {
        MessageContainer mc = new MessageContainer();
        mc.setId(rs.getInt("id"));
        mc.setName(rs.getString("name"));
        return mc;
    }

}