无法将类型为 ‘java.lang.String’ 的属性值转换为所需的类型 ‘java.sql.Date’。

huangapple go评论86阅读模式
英文:

Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date'

问题

我编写了一个Spring Batch作业,该作业读取CSV文件并将其写入SQL Server数据库。CSV文件具有一些DateTimeStamp类型的字段。我正在使用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

无法将类型为&#39;java.lang.String&#39;的属性值转换为所需的类型&#39;java.sql.Date&#39;,用于属性&#39;dateOfBirth&#39;;

对象&#39;target&#39;中的字段&#39;dateOfBirth&#39;中的字段错误:被拒绝的值[1998-12-31];代码[typeMismatch.target.dateOfBirth,typeMismatch.dateOfBirth,typeMismatch.java.sql.Date,typeMismatch];参数[org.springframework.context.support.DefaultMessageSourceResolvable:codes [target.dateOfBirth,dateOfBirth];参数[];默认消息[dateOfBirth];默认消息[无法将类型为&#39;java.lang.String&#39;的属性值转换为所需的类型&#39;java.sql.Date&#39;,用于属性&#39;dateOfBirth&#39;:找不到匹配的编辑器或转换策略]```

**对于其他日期和时间戳字段(```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.Datejava.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&lt;User&gt; itemReader() {

        FlatFileItemReader&lt;User&gt; flatFileItemReader = new FlatFileItemReader&lt;&gt;();
        flatFileItemReader.setResource(inputResource);
        flatFileItemReader.setName(&quot;CSV-Reader&quot;);
        flatFileItemReader.setLineMapper(lineMapper());
        return flatFileItemReader;
    }

    @Bean
    public LineMapper&lt;User&gt; lineMapper() {

        DefaultLineMapper&lt;User&gt; defaultLineMapper = new DefaultLineMapper&lt;&gt;();
        DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();

        lineTokenizer.setDelimiter(&quot;,&quot;);
        lineTokenizer.setStrict(false);
        lineTokenizer.setNames(new String[]{&quot;firstName&quot;, &quot;lastName&quot;, &quot;dateOfBirth&quot;, &quot;dateOfJoining&quot;,&quot;timeStampReg&quot;});

        BeanWrapperFieldSetMapper&lt;User&gt; fieldSetMapper = new BeanWrapperFieldSetMapper&lt;&gt;();
        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 &#39;java.lang.String&#39; to required type &#39;java.sql.Date&#39; for property &#39;dateOfBirth&#39;;

Field error in object &#39;target&#39; on field &#39;dateOfBirth&#39;: 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 &#39;java.lang.String&#39; to required type &#39;java.sql.Date&#39; for property &#39;dateOfBirth&#39;; nested exception is java.lang.IllegalStateException: Cannot convert value of type &#39;java.lang.String&#39; to required type &#39;java.sql.Date&#39; for property &#39;dateOfBirth&#39;: 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&lt;User&gt; extends BeanWrapperFieldSetMapper&lt;FSMChequePayment&gt; {

	@Override
	protected void initBinder(DataBinder binder) {
		CustomDateEditor editor = new CustomDateEditor(new SimpleDateFormat(&quot;yyyy-MM-dd&quot;), true);
		binder.registerCustomEditor(Date.class, editor);

        CustomDateEditor editorTimeStamp = new CustomDateEditor(new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss.SSSSSS&quot;), true);
		binder.registerCustomEditor(TimeStamp.class,editorTimeStamp);
		
	}
}

and use its object instead of the actual BeanWrapperFieldSetMapperin the flatFileItemReader bean by replacing it with:

MyCustomBeanWrapperFieldSetMapper&lt;User&gt; fieldSetMapper = new MyCustomBeanWrapperFieldSetMapper&lt;&gt;();

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值,但无法转换更复杂的类型。关于BeanWrapperFieldSetMapperJavaDoc文档中提到:

> 要自定义将FieldSet值转换为所需类型以便注入原型的方式,有几种选择。您可以通过customEditors属性直接注入PropertyEditor实例,或者可以覆盖createBinder(Object)和initBinder(DataBinder)方法,或者可以提供自定义的FieldSet实现。您还可以使用ConversionService通过conversionService属性将其转换为所需类型。

我建议根据最适合您需求的选项尝试一些替代方案。

编辑: 一个可能的解决方案是简单地使用ApplicationConversionService类,这是Spring Boot提供的开箱即用的功能。我在GitHub上设置了一个可工作的示例,如果你想查看我的解决方案,更重要的是,我的假设是关于你的项目。请注意,在我的示例项目中,我使用了java.sql.*类,因为ApplicationConversionService在这些类中可以正常工作,看起来。

@Bean
FieldSetMapper&lt;User&gt; fieldSetMapper() {
    BeanWrapperFieldSetMapper&lt;User&gt; fieldSetMapper = new BeanWrapperFieldSetMapper&lt;&gt;();
    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&lt;User&gt; fieldSetMapper() {
    BeanWrapperFieldSetMapper&lt;User&gt; fieldSetMapper = new BeanWrapperFieldSetMapper&lt;&gt;();
    fieldSetMapper.setTargetType(User.class);
    fieldSetMapper.setConversionService(ApplicationConversionService.getSharedInstance());
    return fieldSetMapper;
}

huangapple
  • 本文由 发表于 2020年10月9日 04:57:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/64270482.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定