英文:
Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date'
问题
我编写了一个Spring Batch作业,该作业读取CSV文件并将其写入SQL Server数据库。CSV文件具有一些Date
和TimeStamp
类型的字段。我正在使用FlatFileItemReader和JdbcBatchItemWriter。
CSV中的日期格式为yyyy-MM-dd,
时间戳格式为yyyy-MM-dd HH:mm:ss.SSSSSS。
注意:我使用的是java.sql.Date和TimeStamp,而不是java.util.Date和TimeStamp。
用户类:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String firstName;
private String lastName;
private Date dateOfBirth;
private Date dateOfJoining;
private TimeStamp timeStampReg;
...
}
我在不同的步骤中使用相同的模型类User
从数据库中读取。
配置类中的Reader如下:
@Configuration
public class BatchConfigClass {
// 第一步
@Bean
public FlatFileItemReader<User> itemReader() {
FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
flatFileItemReader.setResource(inputResource);
flatFileItemReader.setName("CSV-Reader");
flatFileItemReader.setLineMapper(lineMapper());
return flatFileItemReader;
}
@Bean
public LineMapper<User> lineMapper() {
DefaultLineMapper<User> defaultLineMapper = new DefaultLineMapper<>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames(new String[]{"firstName", "lastName", "dateOfBirth", "dateOfJoining", "timeStampReg"});
BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(User.class);
defaultLineMapper.setLineTokenizer(lineTokenizer);
defaultLineMapper.setFieldSetMapper(fieldSetMapper);
return defaultLineMapper;
}
...
}
运行作业时,我遇到以下错误:
在资源中的第1行解析错误:Path to the CSV file
无法将类型为'java.lang.String'的属性值转换为所需的类型'java.sql.Date',用于属性'dateOfBirth';
对象'target'中的字段'dateOfBirth'中的字段错误:被拒绝的值[1998-12-31];代码[typeMismatch.target.dateOfBirth,typeMismatch.dateOfBirth,typeMismatch.java.sql.Date,typeMismatch];参数[org.springframework.context.support.DefaultMessageSourceResolvable:codes [target.dateOfBirth,dateOfBirth];参数[];默认消息[dateOfBirth];默认消息[无法将类型为'java.lang.String'的属性值转换为所需的类型'java.sql.Date',用于属性'dateOfBirth':找不到匹配的编辑器或转换策略]```
**对于其他日期和时间戳字段(```dateOfJoining```和```timeStampReg```),会出现相同的错误。**
**编辑:**
我通过以下解决方案解决了“Date”类型字段的错误,但对于“TimeStamp”类型字段仍然出现相同的错误。
我创建了一个“自定义BeanWrapperFieldSetMapper”,并覆盖其“initBinder”以添加“CustomDateEditor”。
```java
public class MyCustomBeanWrapperFieldSetMapper<User> extends BeanWrapperFieldSetMapper<User> {
@Override
protected void initBinder(DataBinder binder) {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true);
binder.registerCustomEditor(Date.class, editor);
CustomDateEditor editorTimeStamp = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS"), true);
binder.registerCustomEditor(TimeStamp.class, editorTimeStamp);
}
}
然后,在flatFileItemReader
bean中使用它的对象,替换实际的BeanWrapperFieldSetMapper
,如下所示:
MyCustomBeanWrapperFieldSetMapper<User> fieldSetMapper = new MyCustomBeanWrapperFieldSetMapper<>();
附注:自定义编辑器对java.sql.Date
和java.sql.TimeStamp
不起作用。所以我不得不切换到java.util.Date
。这解决了“Date”类型的问题,但对于“TimeStamp”类型的错误仍然存在。
英文:
I've written a spring batch job that reads a CSV and writes into SQL server db. The CSV file has some fields of type Date
and TimeStamp
. I'm using FlatFileItemReader and JdbcBatchItemWriter.
The Date format in my CSV is yyyy-MM-dd
and the TimeStamp format is yyyy-MM-dd HH:mm:ss.SSSSSS
NOTE: I'm using java.sql.Date and TimeStamp, NOT java.util.Date and TimeStamp
User class:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User{
private String firstName;
private String lastName;
private Date dateOfBirth;
private Date dateOfJoining;
private TimeStamp timeStampReg;
...
I use the same model class User
to read from the DB in a different step.
The Reader in Configuration Class looks like:
@Configuration
public class BatchConfigClass{
//Step 1
@Bean
public FlatFileItemReader<User> itemReader() {
FlatFileItemReader<User> flatFileItemReader = new FlatFileItemReader<>();
flatFileItemReader.setResource(inputResource);
flatFileItemReader.setName("CSV-Reader");
flatFileItemReader.setLineMapper(lineMapper());
return flatFileItemReader;
}
@Bean
public LineMapper<User> lineMapper() {
DefaultLineMapper<User> defaultLineMapper = new DefaultLineMapper<>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames(new String[]{"firstName", "lastName", "dateOfBirth", "dateOfJoining","timeStampReg"});
BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(User.class);
defaultLineMapper.setLineTokenizer(lineTokenizer);
defaultLineMapper.setFieldSetMapper(fieldSetMapper);
return defaultLineMapper;
}
...
On running the job, I get the errors:
Parsing error at line: 1 in resource=Path to the CSV file
Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date' for property 'dateOfBirth';
Field error in object 'target' on field 'dateOfBirth': rejected value [1998-12-31]; codes [typeMismatch.target.dateOfBirth,typeMismatch.dateOfBirth,typeMismatch.java.sql.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [target.dateOfBirth,dateOfBirth]; arguments []; default message [dateOfBirth]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date' for property 'dateOfBirth'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.sql.Date' for property 'dateOfBirth': no matching editors or conversion strategy found]
It gives the same error for other date and timestamp fields(dateOfJoining
and timeStampReg
)
EDIT:
I resolved the error for the Date
type fields by the following solution, But I'm still getting the same error for TimeStamp
type field.
I created a custom BeanWrapperFieldSetMapper
and override its initBinder
to add a CustomDateEditor
.
public class MyCustomBeanWrapperFieldSetMapper<User> extends BeanWrapperFieldSetMapper<FSMChequePayment> {
@Override
protected void initBinder(DataBinder binder) {
CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true);
binder.registerCustomEditor(Date.class, editor);
CustomDateEditor editorTimeStamp = new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS"), true);
binder.registerCustomEditor(TimeStamp.class,editorTimeStamp);
}
}
and use its object instead of the actual BeanWrapperFieldSetMapper
in the flatFileItemReader
bean by replacing it with:
MyCustomBeanWrapperFieldSetMapper<User> fieldSetMapper = new MyCustomBeanWrapperFieldSetMapper<>();
PS: The Custom Editor didn't work for java.sql.Date
and java.sql.TimeStamp
. So I had to Switch to java.util.Date
. That resolved it for Date
type but the error still persists for TimeStamp
type.
答案1
得分: 3
似乎你的批处理只能将行拆分为String
值,但无法转换更复杂的类型。关于BeanWrapperFieldSetMapper
的JavaDoc文档中提到:
> 要自定义将FieldSet值转换为所需类型以便注入原型的方式,有几种选择。您可以通过customEditors属性直接注入PropertyEditor实例,或者可以覆盖createBinder(Object)和initBinder(DataBinder)方法,或者可以提供自定义的FieldSet实现。您还可以使用ConversionService通过conversionService属性将其转换为所需类型。
我建议根据最适合您需求的选项尝试一些替代方案。
编辑: 一个可能的解决方案是简单地使用ApplicationConversionService
类,这是Spring Boot提供的开箱即用的功能。我在GitHub上设置了一个可工作的示例,如果你想查看我的解决方案,更重要的是,我的假设是关于你的项目。请注意,在我的示例项目中,我使用了java.sql.*
类,因为ApplicationConversionService
在这些类中可以正常工作,看起来。
@Bean
FieldSetMapper<User> fieldSetMapper() {
BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(User.class);
fieldSetMapper.setConversionService(ApplicationConversionService.getSharedInstance());
return fieldSetMapper;
}
英文:
It sounds as though your batch is only able to split your lines into String
values, but fails to convert the more exotic types. The JavaDoc for BeanWrapperFieldSetMapper
says:
> To customize the way that FieldSet values are converted to the desired type for injecting into the prototype there are several choices. You can inject PropertyEditor instances directly through the customEditors property, or you can override the createBinder(Object) and initBinder(DataBinder) methods, or you can provide a custom FieldSet implementation. You can also use a ConversionService to convert to the desired type through the conversionService property.
I suggest experimenting with some of those alternatives based on which ones fit your need best.
EDIT: A possible solution can be to simply use the ApplicationConversionService
class, which Spring Boot provides out of the box. I set up a working example on GitHub if you want to take a look at my solution and, more importantly, my assumptions about your project. Note that I'm using the java.sql.*
classes in my example project because the ApplicationConversionService
works fine with those, seemingly.
@Bean
FieldSetMapper<User> fieldSetMapper() {
BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(User.class);
fieldSetMapper.setConversionService(ApplicationConversionService.getSharedInstance());
return fieldSetMapper;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论