java - 从自定义 ItemReader 访问时无法强制转换 FlatFileItemReader

标签 java spring spring-batch

我目前有一个应用程序,我正在尝试诊断我在设置中所做的错误,但没有运气确定为什么它在非常特定的情况之外无法工作。

首先是我正在使用的代码。

配置.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 模式移至自定义 Reader 类的构造函数中,或者将其放在配置文件中,则它可以正常工作。但是,我无法弄清楚如何在这些配置中使用作业和步骤上下文(从我的测试看来,构造函数在您可以访问步骤和 jobContext 之前执行,并且我永远无法弄清楚放入 Config 类中时如何访问。)。至少对我来说,将 Reader 代码放在自己的文件中而不是填充到构造函数中看起来更干净。

简而言之,有没有办法修复这个操作系统,使其在自己的阅读器类中可以工作?我这样做是否错误并使用了不良做法?也许是两者的混合?如果有任何遗漏,请询问,我会尽力澄清。

最佳答案

因此,在评论中的一些帮助下,我发现答案非常简单。这是我的解决方案。

首先,将粗体代码添加到抽象类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();**
}

手动执行读取调用将阻止它返回比您的读者类所需的更多内容。然后在 reader 类中编辑以下内容

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

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

这只会返回您创建的对象,从而解决问题。

关于java - 从自定义 ItemReader 访问时无法强制转换 FlatFileItemReader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43269834/

相关文章:

java - Toast 和 Progress 对话框边缘被切断

java - 使用 SAAJ 的 Java SOAP 客户端出现错误

java - 谷歌应用程序引擎中的安全错误

java - Jackson 反序列化忽略属性无法与 @JsonView 正常工作

java - 为什么 Eclipse 不会在断点处停止?

java - Spring Batch 测试完成后失败,因为上下文不活动

java - 辅助功能服务崩溃并且无法重新启动

java - Hibernate 实体更新现有行而不是使用 saveAndFlush 创建新行

java - 使用FlatFileItemReader读取csv文件,遇到空列时抛出异常

spring - @BeforeStep 未在 AsyncProcessor 中调用