Bean属性不可读或具有无效的getter方法:getter的返回类型是否与setter的参数类型匹配? 春批

我正在开发Spring Batch CompositeItemReader & Writer示例。 我开发了XML文件并且能够成功编译代码,但是当运行mu示例代码时,会出现以下错误。 不确定出了什么问题?

 org.springframework.beans.NotReadablePropertyException: Invalid property 'customerNumber' of bean class [java.lang.String]: Bean property 'customerNumber' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:619) at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:610) at org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor.extract(BeanWrapperFieldExtractor.java:57) at org.springframework.batch.item.file.transform.ExtractorLineAggregator.aggregate(ExtractorLineAggregator.java:54) at org.springframework.batch.item.file.FlatFileItemWriter.write(FlatFileItemWriter.java:267) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) 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 com.sun.proxy.$Proxy4.write(Unknown Source) at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175) at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151) at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274) at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199) 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.CompositeMain.main(CompositeMain.java:24) 

JDBC复合项目 – 读者job.xml

                                                                         <!--  -->                               

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 } 

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; public Integer getCustomerNumber() { return customerNumber; } public void setCustomerNumber(Integer customerNumber) { this.customerNumber = customerNumber; } public String getCustomerName() { return customerName; } public void setCustomerName(String customerName) { this.customerName = customerName; } public String getContactLastName() { return contactLastName; } public void setContactLastName(String contactLastName) { this.contactLastName = contactLastName; } public String getContactFirstName() { return contactFirstName; } public void setContactFirstName(String contactFirstName) { this.contactFirstName = contactFirstName; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getAddressLine1() { return addressLine1; } public void setAddressLine1(String addressLine1) { this.addressLine1 = addressLine1; } public String getAddressLine2() { return addressLine2; } public void setAddressLine2(String addressLine2) { this.addressLine2 = addressLine2; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getState() { return state; } public void setState(String state) { this.state = state; } public String getPostalCode() { return postalCode; } public void setPostalCode(String postalCode) { this.postalCode = postalCode; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public Integer getSalesRepEmployeeNumber() { return salesRepEmployeeNumber; } public void setSalesRepEmployeeNumber(Integer salesRepEmployeeNumber) { this.salesRepEmployeeNumber = salesRepEmployeeNumber; } public Double getCreditLimit() { return creditLimit; } public void setCreditLimit(Double creditLimit) { this.creditLimit = creditLimit; } /*@Override public String toString() { return customerNumber + "|" + customerName + "|" + contactLastName + "|" + contactFirstName + "|" + phone+ "|" + addressLine1 + "|" + addressLine2 + "|" + city + "|" + state+ "|" + postalCode + "|" + country+ "|" + salesRepEmployeeNumber + "|" + creditLimit; }*/ } 

CompositeMain.java

 public class CompositeMain { @SuppressWarnings("resource") public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("composite/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 !!"); } } 

我的DB详情:

 mysql> desc customers; +------------------------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +------------------------+-------------+------+-----+---------+-------+ | customerNumber | int(11) | NO | PRI | NULL | | | customerName | varchar(50) | NO | | NULL | | | contactLastName | varchar(50) | NO | | NULL | | | contactFirstName | varchar(50) | NO | | NULL | | | phone | varchar(50) | NO | | NULL | | | addressLine1 | varchar(50) | NO | | NULL | | | addressLine2 | varchar(50) | YES | | NULL | | | city | varchar(50) | NO | | NULL | | | state | varchar(50) | YES | | NULL | | | postalCode | varchar(15) | YES | | NULL | | | country | varchar(50) | NO | | NULL | | | salesRepEmployeeNumber | int(11) | YES | MUL | NULL | | | creditLimit | double | YES | | NULL | | +------------------------+-------------+------+-----+---------+-------+ 13 rows in set (0.14 sec) mysql> desc employees; +----------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+--------------+------+-----+---------+-------+ | employeeNumber | int(11) | NO | PRI | NULL | | | lastName | varchar(50) | NO | | NULL | | | firstName | varchar(50) | NO | | NULL | | | extension | varchar(10) | NO | | NULL | | | email | varchar(100) | NO | | NULL | | | officeCode | varchar(10) | NO | MUL | NULL | | | reportsTo | int(11) | YES | MUL | NULL | | | jobTitle | varchar(50) | NO | | NULL | | +----------------+--------------+------+-----+---------+-------+ 8 rows in set (0.01 sec) 

我看到问题已经存在: http : //forum.spring.io/forum/spring-projects/container/112929-concurrent-problem-with-beanwrapperimpl-getpropertyvalue-in-3-1

的pom.xml

  1.8 4.2.4.RELEASE 3.0.1.RELEASE 5.1.31 2.8    org.springframework spring-core ${springframework.version}   org.springframework spring-jdbc ${springframework.version}    org.springframework spring-oxm ${springframework.version}   org.springframework spring-jdbc ${springframework.version}    org.springframework.batch spring-batch-core ${springbatch.version}   org.springframework.batch spring-batch-infrastructure ${springbatch.version}   mysql mysql-connector-java ${mysql.version}   joda-time joda-time ${joda-time.version}   junit junit 4.12   

CustomerMapper.java

 public class CustomerMapper implements RowMapper{ @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{ @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; } } 

CompositeCursorItemReader.java

 public class CompositeCursorItemReader implements ItemStreamReader { private List<AbstractCursorItemReader> cursorItemReaders; private UnifyingItemsMapper unifyingMapper; @Override public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { // read from all registered readers List items = new ArrayList(); for (AbstractCursorItemReader cursorItemReader : cursorItemReaders) { items.add(cursorItemReader.read()); } // delegate to mapper return unifyingMapper.mapItems(items); } @Override public void update(ExecutionContext executionContext) { for (ItemStream itemStream : cursorItemReaders) { itemStream.update(executionContext); } } @Override public void close() throws ItemStreamException { for (ItemStream itemStream : cursorItemReaders) { itemStream.close(); } } @Override public void open(ExecutionContext executionContext) throws ItemStreamException { for (ItemStream itemStream : cursorItemReaders) { itemStream.open(executionContext); } } public void setUnifyingMapper(UnifyingItemsMapper mapper) { this.unifyingMapper = mapper; } public void setCursorItemReaders(List<AbstractCursorItemReader> cursorItemReaders) { this.cursorItemReaders = cursorItemReaders; } } 

UnifyingItemsMapper.java

 public interface UnifyingItemsMapper { T mapItems(List items) throws Exception; } 

Spring试图从String类中获取属性cutomerNumber

  Invalid property 'customerNumber' of bean class [java.lang.String] 

这是错误的,因为String不应该被配置为作业步骤的Item ,这个上下文中的Item应该是Customer

除了一个bean之外,你的bean配置正确: compositeItemReader

这个bean的read方法返回一个String而不是Customer ,这是因为:

 public class CompositeCursorItemReader implements ItemStreamReader { /** Registered ItemStreamReaders. */ private List> cursorItemReaders; /** Mandatory Unifying Mapper Implementation. */ private UnifyingItemsMapper unifyingMapper; @Override public T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException { // read from all registered readers List items = new ArrayList(); for (AbstractCursorItemReader cursorItemReader : cursorItemReaders) { items.add(cursorItemReader.read()); } // delegate to mapper return unifyingMapper.mapItems(items); } } 

其属性UnifyingMapper配置如下:

     

这是您正在使用的UnifyingItemsMapper的实现:

  public class DefaultUnifyingStringItemsMapper implements UnifyingItemsMapper { /** {@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; } } } 

解决方案是创建一个实现UnifyingItemsMapper的新类,并为CompositeCursorItemReader#unifyingMapper配置它

或者,如果您不需要UnifyingItemsMapper itemReader直接使用itemReader

              

您将您的类Customer声明为:

 public class Customer implements Serializable{ private static final long serialVersionUID = 1L; private Integer customerNumber; private String customerName; private String contactLastName; private String contactFirstName; .... // setters and getters } 

您的所有字段都是私有的,您还没有实现公共getter / setter方法。 这样做,你的问题将得到解决。