Ad

Failed To Convert Property Value Of Type 'java.lang.String' To Required Type 'java.sql.Date'

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 BeanWrapperFieldSetMapperin 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.

Ad

Answer

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

Ad
source: stackoverflow.com
Ad