当从自定义项目读取器访问FlatFileItemReader

问题描述:

我目前有一个应用程序,我试图诊断什么在我做了不正确的设置,并没有任何运气,以确定为什么它不工作以外的非常具体情况。当从自定义项目读取器访问FlatFileItemReader

首先我正在使用的代码。

Configuration.java

@EnableBatchProcessing 
@SpringBootApplication(scanBasePackages="com.lcbo") 
@EnableIntegration 
public class COnfig { 

    @Autowired 
    private JobBuilderFactory jobBuilderFactory; 

    @Autowired 
    private StepBuilderFactory stepBuilderFactory; 

    @Autowired 
    private LCBOInventoryTrackerProperties inventoryTrackerProperties; 

    @Bean 
    public Job processLCBOInventory(@Qualifier("getLCBOStoreDataStep") final Step getLCBOStoreDataStep) { 
     return jobBuilderFactory 
       .get("processLCBOInventory") 
       .incrementer(new RunIdIncrementer()) 
       .start(getLCBOStoreDataStep) 
       .build(); 

    } 

    /** 
    * This tasklet downloads the .zip file, unzips, and saves it in the appropriate folder under resources. 
    * Execute at 6am daily 
    * 
    //  * @param AcquireDataFileTasklet acquireDataFiles 
    * @return Step - returns Step status; either SUCCESS or FAILURE 
    */ 

    @Bean 
    public Step getCurrentLCBODataStep(final AcquireDataFileTasklet acquireDataFiles, 
             final ExecutionContextPromotionListener listener) { 
     return stepBuilderFactory 
       .get("getCurrentLCBODataStep") 
       .tasklet(acquireDataFiles) 
       .allowStartIfComplete(true) 
       .listener(listener) 
       .build(); 
    } 

    @Bean 
    public Step getLCBOStoreDataStep(final LCBOStoreReader lcboStoreReader, 
            final LCBOStoreWriter lcboStoreWriter) { 

     return stepBuilderFactory 
       .get("getLCBOStoreDataStep") 
       .<LCBOStore, LCBOStore>chunk(inventoryTrackerProperties.getDefaults().getChunkSize()) 
       .reader(lcboStoreReader) 
       .writer(lcboStoreWriter) 
       .build(); 
    } 
} 

读者类

@Component 
public class LCBOStoreReader extends AbstractLCBOReader implements ItemReader, InterstepDataRetriever { 

    private static final Logger log = LoggerFactory.getLogger(LCBOStoreReader.class); 

    @Override 
    public ItemReader<LCBOStore> read() throws UnexpectedInputException, ParseException, NonTransientResourceException { 
     Class<LCBOStore> classType = LCBOStore.class; 

     return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores()); 
    } 
/* 
    @Override 
    public void beforeStep(final StepExecution stepExecution) { 
     JobExecution jobExecution = stepExecution.getJobExecution(); 
     ExecutionContext jobContext = jobExecution.getExecutionContext(); 
     this.currentWorkingDate = (String) jobContext.get("currentWorkingDateKey"); 
    } 
*/ 
    @Override 
    public void retrieveInterstepDataFromJobContext(final ExecutionContext jobContext) { 
     this.currentCSVFilePath = (String) jobContext.get("currentCSVFilePathKey"); 
    } 
} 

和其延伸(因为FlatFileItemReader设置用于通过多个阅读器)的类

public abstract class AbstractLCBOReader { 

    @Autowired 
    protected LCBOInventoryTrackerProperties inventoryTrackerProperties; 

    protected String currentCSVFilePathKey; 
    protected String currentCSVFilePath; 

    private static final Logger log = LoggerFactory.getLogger(AbstractLCBOReader.class); 

    protected <T> ItemReader<T> createCSVReader(final Class<T> classType, 
               final String currentCSVFilePath, 
               final LCBOFileDetailsProperties properties) { 

     FlatFileItemReader<T> reader = new FlatFileItemReader<>(); 
     // Skip a line to ignore the header information in these files 
     reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile()); 
     reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName())); 
     reader.setLineMapper(createLineMapper(classType, properties)); 
     reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); 
     reader.setEncoding("utf8"); 

     return reader; 
    } 

    private <T> LineMapper<T> createLineMapper(final Class<T> classType, final LCBOFileProperties.LCBOFileDetailsProperties properties) { 
     DefaultLineMapper<T> lineMapper = new DefaultLineMapper<>(); 
     lineMapper.setLineTokenizer(createLineTokenizer(properties)); 
     lineMapper.setFieldSetMapper(createFieldSetMapper(classType)); 

     return lineMapper; 
    } 

    private <T> FieldSetMapper<T> createFieldSetMapper(final Class<T> classType) { 
     BeanWrapperFieldSetMapper<T> fieldSetMapper = new BeanWrapperFieldSetMapper<>(); 
     fieldSetMapper.setTargetType(classType); 

     return fieldSetMapper; 
    } 

    private LineTokenizer createLineTokenizer(final LCBOFileProperties.LCBOFileDetailsProperties properties) { 
     LCBOFileProperties.Column[] columns = properties.getColumns(); 
     int[] columnIndexes = new int[columns.length]; 
     String[] columnNames = new String[columns.length]; 

     // populating the columnIndexes 
     for (int i = 0; i < columns.length; i++) { 
      columnIndexes[i] = columns[i].getColumnIndex(); 
      columnNames[i] = columns[i].getColumnName(); 
     } 

     DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer(); 
     lineTokenizer.setIncludedFields(columnIndexes); 
     lineTokenizer.setNames(columnNames); 
     lineTokenizer.setDelimiter(","); 
     lineTokenizer.setQuoteCharacter('"'); 

     return lineTokenizer; 
    } 
} 

的执行此操作时会出现错误该对象不能从FlatFileItemreader强制转换为作为createCSVReader中第一个参数传递的对象。这是一个例子。

public class LCBOStore { 

    private Long id; 
    private String addressLineOne; 
    private String addressLineTwo; 
    private String city; 
    private String postalCode; 
    private String latitude; 
    private String longitude; 
    private String updatedAt; //Convert to Date 

    public LCBOStore(final Long id, final String addressLineOne, final String addressLineTwo, final String city, 
        final String postalCode, final String latitude, final String longitude, final String updatedAt) { 
     this.id = id; 
     this.addressLineOne = addressLineOne; 
     this.addressLineTwo = addressLineTwo; 
     this.city = city; 
     this.postalCode = postalCode; 
     this.latitude = latitude; 
     this.longitude = longitude; 
     this.updatedAt = updatedAt; 
    } 

    public Long getId() { 
     return id; 
    } 

    public String getAddressLineOne() { 
     return addressLineOne; 
    } 

    public String getAddressLineTwo() { 
     return addressLineTwo; 
    } 

    public String getCity() { 
     return city; 
    } 

    public String getPostalCode() { 
     return postalCode; 
    } 

    public String getLatitude() { 
     return latitude; 
    } 

    public String getLongitude() { 
     return longitude; 
    } 

    public String getUpdatedAt() { 
     return updatedAt; 
    } 

    public void setId(final Long id) { 
     this.id = id; 
    } 

    public void setAddressLineOne(final String addressLineOne) { 
     this.addressLineOne = addressLineOne; 
    } 

    public void setAddressLineTwo(final String addressLineTwo) { 
     this.addressLineTwo = addressLineTwo; 
    } 

    public void setCity(final String city) { 
     this.city = city; 
    } 

    public void setPostalCode(final String postalCode) { 
     this.postalCode = postalCode; 
    } 

    public void setLatitude(final String latitude) { 
     this.latitude = latitude; 
    } 

    public void setLongitude(final String longitude) { 
     this.longitude = longitude; 
    } 

    public void setUpdatedAt(final String updatedAt) { 
     this.updatedAt = updatedAt; 
    } 

    @Override 
    public String toString() { 
     return "StoreDBModel [id=" + id + ", addressLineOne=" + addressLineOne + ", city=" + city 
       + ", postalCode=" + postalCode + ", latitude=" + latitude + ", longitude=" 
       + longitude + ", updatedAt=" + updatedAt + "]"; 
    } 
} 

现在,如果我动议存在createCSVReader到定制的阅读器类的构造函数的FlatFileItemReader模式,还是有它,所以它的配置文件中,它工作正常。然而,我无法弄清楚如何在这些配置中使用作业和步骤上下文(构造函数在您可以访问步骤和jobContext之前执行,它似乎来自于我的测试,并且在放入Config类时我永远不会知道如何访问)。此外,至少对于我来说,让它自己的文件中的Reader代码不会塞入构造函数中看起来更干净。

所以简而言之,有没有一种方法可以解决这个问题,让它在自己的阅读器类中工作?我是否做得不正确,并使用不好的做法?也许是两者的混合?如果有什么遗漏,请询问,我会尝试澄清。

+0

您的阅读器返回'ItemReader ',因为它应该在委托项读取器上调用read方法并返回'YourObject'。读取方法的全部目的是返回实际的对象而不是潜在的项目读取器。 –

+0

'LCBOStoreReader.read()'可能会返回'LCBOStore',而不是'ItemReader' ... – OhadR

+0

知道这将是简单的事情,阅读功能正在按预期工作,只为根csvParser类,没有一个自动方式来读取。无论哪种方式,感谢您的支持,它帮助我找到了解决方案。 – canadiancreed

因此,我发现答案很简单,在评论中提供了一些帮助。这是我的解决方案。

首先,粗体显示的代码添加到抽象类createCSVWriter方法

**protected <T> T** createCSVReader(final Class<T> classType, 
           final String currentCSVFilePath, 
           final LCBOFileDetailsProperties properties) throws Exception { 

    FlatFileItemReader<T> reader = new FlatFileItemReader<>(); 
    // Skip a line to ignore the header information in these files 
    reader.setLinesToSkip(properties.getNumberOfLinesToSkipInFile()); 
    reader.setResource(new FileSystemResource(currentCSVFilePath + File.separator + properties.getFileName())); 
    reader.setLineMapper(createLineMapper(classType, properties)); 
    reader.setRecordSeparatorPolicy(new DefaultRecordSeparatorPolicy()); 
    reader.setEncoding("utf8"); 

    **return reader.read();** 
} 

手工完成的读取调用将阻止其返回更多的则需要为您的读取器类。然后在读者类中编辑以下内容

@Override 
public **LCBOStore** read() throws **Exception**, UnexpectedInputException, ParseException, NonTransientResourceException { 
    Class<LCBOStore> classType = LCBOStore.class; 

    return createCSVReader(classType, currentCSVFilePath, inventoryTrackerProperties.getLCBOFilPropertiess().getStores()); 
} 

这只是返回您创建的对象并因此问题解决。