java.lang.ClassCastException: java.lang.String cannot be cast to com.common.batch.model.Customer - Spring Batch CompositeItemReader and Writter

倖福魔咒の 提交于 2019-12-25 06:24:00

问题


I am developing Spring Batch CompositeItemReader and Writter example. In this program I am trying to read data two tables from mysql db table and write to single XML file. When trying to do that I see following error is coming:

java.lang.ClassCastException: java.lang.String cannot be cast to com.common.batch.model.Customer
    at com.common.batch.processor.CustomerProcessor.process(CustomerProcessor.java:1)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:126)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:293)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:192)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:77)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:368)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:198)
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:162)
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:141)
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:304)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
    at com.common.batch.main.CompositeXMLMain.main(CompositeXMLMain.java:24)

I don't have any clue in solving this issue. Please guide me. Employee.java

public class Employee implements Serializable{
    private static final long serialVersionUID = 1L;

    private Integer employeeNumber;
    private String lastName;
    private String firstName;
    private String extension;
    private String email;
    private String officeCode;
    private Integer reportsTo;
    private String jobTitle;
    // setters and getters
@Override
    public String toString() {
        return customerNumber + "|" + customerName + "|" + contactLastName + "|" + contactFirstName + "|" + 
                phone+ "|" + addressLine1 + "|" + addressLine2 + "|" + city + "|" + state+ "|" + postalCode + "|" + 
                country+ "|" + salesRepEmployeeNumber + "|" + creditLimit;
    }
    }

Customer.java

public class Customer implements Serializable{
    private static final long serialVersionUID = 1L;

    private Integer customerNumber;
    private String customerName;
    private String contactLastName;
    private String contactFirstName;
    private String phone;
    private String addressLine1;
    private String addressLine2;
    private String city;
    private String state;
    private String postalCode;
    private String country;
    private Integer salesRepEmployeeNumber;
    private Double creditLimit;
    // setters and getters
@Override
    public String toString() {
        return employeeNumber + "|"+ lastName + "|" + firstName + "|"+ extension + 
                "|" + email + "|" + officeCode+ "|" + reportsTo + "|" + jobTitle;
}
}

xml-jdbc-composite-item-reader-job.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">

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

    <!-- JobRepository and JobLauncher are configuration/setup classes -->
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />

    <bean id="jobLauncher"  class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository" />
    </bean>


    <!-- Step will need a transaction manager -->
    <bean id="transactionManager"
        class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />


    <!-- =========================================================== -->    
    <job id="compositeJdbcReaderJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="compositeJdbcReaderStep" next="compositeJdbcReaderStep2">
            <tasklet>
                <chunk reader="compositeItemReader1" writer="itemWriter1" processor="itemCustomerProcessor" 
                commit-interval="5" />
            </tasklet>
        </step>

        <step id="compositeJdbcReaderStep2">
            <tasklet>
                <chunk reader="compositeItemReader2" writer="itemWriter2" processor="itemEmployeeProcessor" 
                commit-interval="5" />
            </tasklet>
        </step>
    </job>


    <!-- ============= Composite Item Reader ================ -->
    <bean id="compositeItemReader1" class="com.common.batch.reader.CompositeCursorItemReader">
        <property name="unifyingMapper">
            <bean class="com.common.batch.mapper.DefaultUnifyingStringItemsMapper" />
        </property>
        <property name="cursorItemReaders">
            <list>
                <ref bean="itemReader1" />
            </list>
        </property>
    </bean>

    <bean id="compositeItemReader2" class="com.common.batch.reader.CompositeCursorItemReader">
        <property name="unifyingMapper">
            <bean class="com.common.batch.mapper.DefaultUnifyingStringItemsMapper" />
        </property>
        <property name="cursorItemReaders">
            <list>
                <ref bean="itemReader2" />                 
            </list>
        </property>
    </bean>


    <!-- ========== ItemReader =============== -->
    <bean id="itemReader1" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ ${select.sql.customers} ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.CustomerMapper" />
        </property>
    </bean>


    <bean id="itemReader2" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ ${select.sql.employees} ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.EmployeeMapper" />
        </property>
    </bean>


    <!-- ItemWritter -->
    <bean id="itemWriter1" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/customers.xml" />

        <property name="marshaller" ref="customerUnmarshaller" />

        <property name="rootTagName" value="customers" />
    </bean>

    <bean id="itemWriter2" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/customers.xml" />

        <property name="marshaller" ref="employeeUnmarshaller" />

        <property name="rootTagName" value="employees" />
    </bean>

    <!-- ======= Employee Unmarshaller ======== -->
    <bean id="employeeUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="aliases">
            <util:map id="aliases">
                <entry key="employee" value="com.common.batch.model.Employee" />
            </util:map>
        </property>
    </bean>

        <!-- ======= Customer Unmarshaller ======== -->
    <bean id="customerUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="aliases">
            <util:map id="aliases">
                <entry key="customer" value="com.common.batch.model.Customer" />
            </util:map>
        </property>
    </bean>


    <bean id="itemCustomerProcessor" class="com.common.batch.processor.CustomerProcessor" />
    <bean id="itemEmployeeProcessor" class="com.common.batch.processor.EmployeeProcessor" />

</beans>

CompositeXMLMain.java

public class CompositeXMLMain {
    @SuppressWarnings("resource")
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("composite/xml-jdbc-composite-item-reader-job.xml");

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

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

        } catch (JobExecutionAlreadyRunningException | JobRestartException
                | JobInstanceAlreadyCompleteException | JobParametersInvalidException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
        System.out.println("Done !!");
    }
}

Edit-1: CustomerProcessor.java

public class CustomerProcessor implements ItemProcessor<Customer, Customer>{

    @Override
    public Customer process(Customer result) throws Exception {
        System.out.println("Processing result :"+result);

        return result;
    }
}

EmployeeProcessor.java

public class EmployeeProcessor implements ItemProcessor<Employee, Employee>{

    @Override
    public Employee process(Employee result) throws Exception {
        System.out.println("Processing result :"+result);
        return result;
    }
}

Edit-2: CustomerMapper.java

public class CustomerMapper implements RowMapper<Customer>{

    @Override
    public Customer mapRow(ResultSet rs, int rowNum) throws SQLException {
        Customer customer = new Customer();
        customer.setCustomerNumber(rs.getInt("customerNumber"));
        customer.setCustomerName(rs.getString("customerName"));
        customer.setContactLastName(rs.getString("contactLastName"));
        customer.setContactFirstName(rs.getString("contactFirstName"));
        customer.setPhone(rs.getString("phone"));
        customer.setAddressLine1(rs.getString("addressLine1"));
        customer.setAddressLine2(rs.getString("addressLine2"));
        customer.setCity(rs.getString("city"));
        customer.setState(rs.getString("state"));
        customer.setPostalCode(rs.getString("postalCode"));
        customer.setCountry(rs.getString("country"));
        customer.setSalesRepEmployeeNumber(rs.getInt("salesRepEmployeeNumber"));
        customer.setCreditLimit(rs.getDouble("creditLimit"));

        return customer;
    }
}

EmployeeMapper.java

public class EmployeeMapper implements RowMapper<Employee>{

    @Override
    public Employee mapRow(ResultSet rs, int rowNum) throws SQLException {
        Employee employee = new Employee();
        employee.setEmployeeNumber(rs.getInt("employeeNumber"));
        employee.setLastName(rs.getString("lastName"));
        employee.setFirstName(rs.getString("firstName"));
        employee.setExtension(rs.getString("extension"));
        employee.setEmail(rs.getString("email"));
        employee.setOfficeCode(rs.getString("officeCode"));
        employee.setReportsTo(rs.getInt("reportsTo"));
        employee.setJobTitle(rs.getString("jobTitle"));

        return employee;
    }
}

Edit-3:

I see couple of issue listed below:

  • I see very weird XML output shown below
  • I only getting second database tables data, first tables data overriding

XML Output?

<?xml version="1.0" encoding="UTF-8"?>
<employees>
   <string>1002|Murphy|Diane|x5800|dmurphy@classicmodelcars.com|1|0|President</string>
   <string>1056|Patterson|Mary|x4611|mpatterso@classicmodelcars.com|1|1002|VP Sales</string>
   <string>1076|Firrelli|Jeff|x9273|jfirrelli@classicmodelcars.com|1|1002|VP Marketing</string>
   <string>1088|Patterson|William|x4871|wpatterson@classicmodelcars.com|6|1056|Sales Manager (APAC)</string>
   <string>1102|Bondur|Gerard|x5408|gbondur@classicmodelcars.com|4|1056|Sale Manager (EMEA)</string>
   <string>1143|Bow|Anthony|x5428|abow@classicmodelcars.com|1|1056|Sales Manager (NA)</string>
   <string>1165|Jennings|Leslie|x3291|ljennings@classicmodelcars.com|1|1143|Sales Rep</string>
   <string>1166|Thompson|Leslie|x4065|lthompson@classicmodelcars.com|1|1143|Sales Rep</string>
   <string>1188|Firrelli|Julie|x2173|jfirrelli@classicmodelcars.com|2|1143|Sales Rep</string>
   <string>1216|Patterson|Steve|x4334|spatterson@classicmodelcars.com|2|1143|Sales Rep</string>
   <string>1286|Tseng|Foon Yue|x2248|ftseng@classicmodelcars.com|3|1143|Sales Rep</string>
   <string>1323|Vanauf|George|x4102|gvanauf@classicmodelcars.com|3|1143|Sales Rep</string>
   <string>1337|Bondur|Loui|x6493|lbondur@classicmodelcars.com|4|1102|Sales Rep</string>
   <string>1370|Hernandez|Gerard|x2028|ghernande@classicmodelcars.com|4|1102|Sales Rep</string>
   <string>1401|Castillo|Pamela|x2759|pcastillo@classicmodelcars.com|4|1102|Sales Rep</string>
   <string>1501|Bott|Larry|x2311|lbott@classicmodelcars.com|7|1102|Sales Rep</string>
   <string>1504|Jones|Barry|x102|bjones@classicmodelcars.com|7|1102|Sales Rep</string>
   <string>1611|Fixter|Andy|x101|afixter@classicmodelcars.com|6|1088|Sales Rep</string>
   <string>1612|Marsh|Peter|x102|pmarsh@classicmodelcars.com|6|1088|Sales Rep</string>
   <string>1619|King|Tom|x103|tking@classicmodelcars.com|6|1088|Sales Rep</string>
   <string>1621|Nishi|Mami|x101|mnishi@classicmodelcars.com|5|1056|Sales Rep</string>
   <string>1625|Kato|Yoshimi|x102|ykato@classicmodelcars.com|5|1621|Sales Rep</string>
   <string>1702|Gerard|Martin|x2312|mgerard@classicmodelcars.com|4|1102|Sales Rep</string>
</employees>

Edit-4: I've corrected

<?xml version="1.0" encoding="UTF-8"?>
<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"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">

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

    <!-- JobRepository and JobLauncher are configuration/setup classes -->
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />

    <bean id="jobLauncher"  class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
        <property name="jobRepository" ref="jobRepository" />
    </bean>


    <!-- Step will need a transaction manager -->
    <bean id="transactionManager"
        class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />


    <!-- =========================================================== -->    
    <job id="compositeJdbcReaderJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="compositeJdbcReaderStep" next="compositeJdbcReaderStep2">
            <tasklet>
                <chunk reader="compositeItemReader1" writer="itemWriter1" commit-interval="5" />
            </tasklet>
        </step>

        <step id="compositeJdbcReaderStep2">
            <tasklet>
                <chunk reader="compositeItemReader2" writer="itemWriter2" commit-interval="5" />
            </tasklet>
        </step>
    </job>


    <!-- ============= Composite Item Reader ================ -->
    <bean id="compositeItemReader1" class="com.common.batch.reader.CompositeCursorItemReader">
        <property name="unifyingMapper">
            <bean class="com.common.batch.mapper.DefaultUnifyingStringItemsMapper" />
        </property>
        <property name="cursorItemReaders">
            <list>
                <ref bean="itemReader1" />
            </list>
        </property>
    </bean>

    <bean id="compositeItemReader2" class="com.common.batch.reader.CompositeCursorItemReader">
        <property name="unifyingMapper">
            <bean class="com.common.batch.mapper.DefaultUnifyingStringItemsMapper" />
        </property>
        <property name="cursorItemReaders">
            <list>
                <ref bean="itemReader2" />                 
            </list>
        </property>
    </bean>


    <!-- ========== ItemReader =============== -->
    <bean id="itemReader1" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ ${select.sql.customers} ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.CustomerMapper" />
        </property>
    </bean>


    <bean id="itemReader2" class="org.springframework.batch.item.database.JdbcCursorItemReader">
        <property name="dataSource" ref="dataSource" />

        <property name="saveState" value="true" />

        <property name="sql">
            <value>
                <![CDATA[ ${select.sql.employees} ]]>
            </value>
        </property>
        <property name="rowMapper">
            <bean class="com.common.batch.mapper.EmployeeMapper" />
        </property>
    </bean>


    <!-- ItemWritter -->
    <bean id="itemWriter1" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/customers.xml" />

        <property name="marshaller" ref="customerUnmarshaller" />

        <property name="rootTagName" value="customers" />
    </bean>

    <bean id="itemWriter2" class="org.springframework.batch.item.xml.StaxEventItemWriter">
        <property name="resource" value="file:xml/customers.xml" />

        <property name="marshaller" ref="employeeUnmarshaller" />

        <property name="rootTagName" value="employees" />
    </bean>

    <!-- ======= Employee Unmarshaller ======== -->
    <bean id="employeeUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="aliases">
            <util:map id="aliases">
                <entry key="employee" value="com.common.batch.model.Employee" />
            </util:map>
        </property>
    </bean>

        <!-- ======= Customer Unmarshaller ======== -->
    <bean id="customerUnmarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
        <property name="aliases">
            <util:map id="aliases">
                <entry key="customer" value="com.common.batch.model.Customer" />
            </util:map>
        </property>
    </bean>


    <bean id="itemCustomerProcessor" class="com.common.batch.processor.CustomerProcessor" />
    <bean id="itemEmployeeProcessor" class="com.common.batch.processor.EmployeeProcessor" />

</beans>

回答1:


i do not understand, why you use CompositeItemReaders if you only use one reader for each, anyways

i guess you copied the DefaultUnifyingStringItemsMapper from this github repo?

source code there is:

public class DefaultUnifyingStringItemsMapper implements UnifyingItemsMapper<String> {

    /** {@inheritDoc} */
    @Override
    public String mapItems(List<?> items) throws Exception {
        if (items != null && items.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (Object item : items) {
                if (item != null) {
                    sb.append(item);
                }
            }
            if (sb.length() > 0) {
                return sb.toString();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }
}

so that is the problem, it will just create a big string which is or is not the kind of item you actually want (to process in processor and writer), right now it won't work with the processor which expects items of type Employee

if you add more readers to the compositeitemreaders, you need to rethink your program especially the writers, what kind of item will they use?



来源:https://stackoverflow.com/questions/36389604/java-lang-classcastexception-java-lang-string-cannot-be-cast-to-com-common-batc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!