【问题标题】:Invalid property 'id' of bean class FlatFileItemReader, file read and Entity used has idbean 类 FlatFileItemReader 的无效属性“id”、文件读取和使用的实体具有 id
【发布时间】:2017-08-07 01:58:07
【问题描述】:

我目前正在开发一个读取 csv 文件的批处理程序,然后使用 hibernate 插入数据,我相信 JPA。

我遇到的错误如下:

org.springframework.beans.NotReadablePropertyException: Invalid property 'id' of bean class [org.springframework.batch.item.file.FlatFileItemReader]: Could not find field for property during fallback access!

我已尝试以下方法来解决此问题:

  • 读取没有名为 id 的列的文件时出现错误。仅尝试了已归档 id 的文件。同样的问题仍然存在
  • 在此处发现问题可能缺少 id 字段(在 SO 线程上找到),因此为 Entity 类中的 id 字段添加了 getter 和 setter。

    @Id @Column(name = "id", nullable = false) 私有长id;

对于没有 id 的文件

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.SEQUENCE) 
private Long id;

但同样的问题发生了。

getter 和 setter 的结构是这样的。

public Long getId() { return id; }

public void setId(final Long id) { this.id = id; }
  • 这里的另一个线程建议使用 Long 而不是 int(它们最初是什么)是原因。原来是这样。
  • 调试器中出现问题的代码引用了这段代码,即save方法

    公共接口 LCBOInventoryRepository 扩展 CrudRepository {

    @Override
    @SuppressWarnings("unchecked")
    public LCBOInventory save(LCBOInventory lcboInventoryObject);
    

但是传递给该方法的每个对象都应该有可用的 Id 信息,如前所述。

根据要求,这里是用于发生此问题的进程的读取器和写入器的代码。

读者:

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

    @Autowired
    public LCBOInventoryReader(final String currentCSVFilePathKey ) {
        this.currentCSVFilePathKey = currentCSVFilePathKey;
    }

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

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

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

    @Override
    public void retrieveInterstepDataFromJobContext(final ExecutionContext jobContext) {
        this.currentCSVFilePath = (String) jobContext.get(currentCSVFilePathKey);
    }
}

这是扩展的抽象类:

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;
    }
}

以及阅读器实现的接口InterstepDataRetriever

public interface InterstepDataRetriever {

    @BeforeStep
    default void retrieveValuesFromStepContext(StepExecution stepExecution) {
        JobExecution jobExecution = stepExecution.getJobExecution();
        ExecutionContext jobContext = jobExecution.getExecutionContext();
        retrieveInterstepDataFromJobContext(jobContext);
    }

    void retrieveInterstepDataFromJobContext(ExecutionContext jobContext);
}

后者对这个问题应该没有任何影响,但为了完整性而包含在内(除了你永远不知道)。

作家(旧):

@Component
public class LCBOInventoryWriter implements ItemWriter<LCBOInventory> {

    @Autowired
    private LCBOInventoryRepository inventoryDAO;

    @Override
    public void write(List<? extends LCBOInventory> lcboInventoryItem) throws Exception {
        inventoryDAO.save(lcboInventoryItem);
    }
}

Writer(New - 这与 Step 放在同一个文件中):

@Bean
public ItemWriter<LCBOStore> writer() {
    HibernateItemWriter writer = new HibernateItemWriter();
    writer.setSessionFactory(sessionFactory);
    System.out.println("writing stuff");
    return writer;
}

这是执行代码时的堆栈跟踪(编辑:堆栈跟踪已更新):

org.hibernate.MappingException: Unknown entity: org.springframework.batch.item.file.FlatFileItemReader
    at org.hibernate.internal.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:783) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.getEntityPersister(SessionImpl.java:1520) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.internal.ForeignKeys.isTransient(ForeignKeys.java:225) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:510) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:83) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:648) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:640) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:635) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.springframework.batch.item.database.HibernateItemWriter.doWrite(HibernateItemWriter.java:140) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.item.database.HibernateItemWriter.write(HibernateItemWriter.java:113) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) ~[spring-tx-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:392) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:135) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.6.RELEASE.jar:4.3.6.RELEASE]
    at com.sun.proxy.$Proxy54.run(Unknown Source) [na:na]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:214) [spring-boot-autoconfigure-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:231) [spring-boot-autoconfigure-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:123) [spring-boot-autoconfigure-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:117) [spring-boot-autoconfigure-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:760) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:747) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1162) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1151) [spring-boot-1.5.1.RELEASE.jar:1.5.1.RELEASE]
    at com.lcbo.config.LCBOBatchConfig.main(LCBOBatchConfig.java:173) [classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_92]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_92]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_92]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_92]
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) [idea_rt.jar:na]

所以简而言之,我不知道它需要什么 id 字段,为什么它认为它是一个实体(没有 @Entity 注释),以及我如何才能满足它的需求,或者修复这样就不需要了。

【问题讨论】:

  • 对于说应该关闭的人,可以发布为什么要改进问题吗?
  • 可以分享一下你的读写器的配置吗?
  • @MichaelMinella 当然。我已经用添加的这些文件更新了问题。
  • 你能提供更多的堆栈跟踪吗?
  • @MichaelMinella 确定。请查看最新编辑

标签: spring hibernate jpa spring-data spring-batch


【解决方案1】:

您确定将正确的Class&lt;T&gt; classType 传递给BeanWrapperFieldSetMapper

此错误使您看起来好像是在传递 FlatFileItemReader 类而不是 LCBOInventory

NotReadablePropertyException:bean 类的无效属性“id” [org.springframework.batch.item.file.FlatFileItemReader]:


更新:请检查作者的write 方法。堆栈跟踪显示错误来自那里,而不是来自您的读者。您是否有可能尝试保留 FlatFileItemReader 对象?

LCBOInventoryWriter.write(LCBOInventoryWriter.java:19)

【讨论】:

  • 只要在 BeanWrapperFieldSetMapper fieldSetMapper = new BeanWrapperFieldSetMapper()上设置断点;并执行。 classType 变量用于 LCBOInventory。
  • 更新的完整堆栈跟踪显示它在 LCBOInventoryWriter.write(LCBOInventoryWriter.java:19 失败,而不是在阅读器中
  • 能否为NotReadablePropertyException 添加异常断点并检查引发异常的对象?我不知道为什么/如何,但看起来 JPA 存储库正在尝试保留 FlatFileItemWriter
  • 我已按要求包含了堆栈跟踪,我想您可能正在做一些事情。如果配置错误,我不会感到惊讶,这是第一个使用 hibernate/JPA 的项目
  • 我的猜测是 Spring Data 误以为 FlatFileItemReader 是一个实体。单独的 Hibernate 肯定不会这样做,因为它没有这样注释,但我对 Spring Data 的内部工作不太熟悉。我个人会尝试放弃 Spring Data。相反,我只会使用 Hibernate 和开箱即用的 HibernateItemWriter 而不是您自定义的。
猜你喜欢
  • 2018-08-30
  • 1970-01-01
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 2016-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多