Không thể chuyển đổi giá trị thuộc tính của loại 'java.lang.String' thành loại bắt buộc 'java.sql.Date'

Oct 08 2020

Tôi đã viết một công việc hàng loạt mùa xuân đọc CSV và ghi vào máy chủ SQL db. Tệp CSV có một số trường thuộc loại Datevà TimeStamp. Tôi đang sử dụng FlatFileItemReader và JdbcBatchItemWriter.

Định dạng Ngày trong CSV của tôi là yyyy-MM-dd và định dạng TimeStamp là yyyy-MM-dd HH: mm: ss.SSSSSSS

LƯU Ý: Tôi đang sử dụng java.sql.Date và TimeStamp, KHÔNG phải java.util.Date và TimeStamp

Hạng người dùng:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User{
    private String firstName;
    private String lastName;
    private Date dateOfBirth;
    private Date dateOfJoining;
    private TimeStamp timeStampReg;
...

Tôi sử dụng cùng một lớp mô hình Userđể đọc từ DB trong một bước khác.

Trình đọc trong Lớp cấu hình trông giống như:

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

Khi thực hiện công việc, tôi gặp các lỗi:

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]

Nó cung cấp cùng một lỗi cho các trường ngày và dấu thời gian khác ( dateOfJoiningvà timeStampReg)

BIÊN TẬP:

Tôi đã giải quyết lỗi cho trường Dateloại bằng giải pháp sau, Nhưng tôi vẫn gặp lỗi tương tự cho TimeStamptrường loại.

Tôi đã tạo một custom BeanWrapperFieldSetMappervà ghi đè nó initBinderđể thêm một 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);
        
    }
}

và sử dụng đối tượng của nó thay vì thực tế BeanWrapperFieldSetMappertrong flatFileItemReaderbean bằng cách thay thế nó bằng:

MyCustomBeanWrapperFieldSetMapper<User> fieldSetMapper = new MyCustomBeanWrapperFieldSetMapper<>();

Tái bút: Trình chỉnh sửa tùy chỉnh không hoạt động cho java.sql.Datevà java.sql.TimeStamp. Vì vậy, tôi đã phải chuyển sang java.util.Date. Điều đó đã giải quyết nó cho Dateloại nhưng lỗi vẫn còn đối với TimeStamploại.

Trả lời

2 ThomasKåsene Oct 08 2020 at 21:27

Nghe có vẻ như lô của bạn chỉ có thể chia các dòng của bạn thành Stringcác giá trị, nhưng không thể chuyển đổi các loại kỳ lạ hơn. Các javadoc choBeanWrapperFieldSetMapper biết:

Để tùy chỉnh cách các giá trị FieldSet được chuyển đổi thành kiểu mong muốn để đưa vào nguyên mẫu, có một số lựa chọn. Bạn có thể đưa trực tiếp các phiên bản PropertyEditor thông qua thuộc tính customEditors hoặc bạn có thể ghi đè các phương thức createBinder (Đối tượng) và initBinder (DataBinder) hoặc bạn có thể cung cấp triển khai FieldSet tùy chỉnh. Bạn cũng có thể sử dụng ConversionService để chuyển đổi sang loại mong muốn thông qua thuộc tính convertService.

Tôi khuyên bạn nên thử nghiệm với một số lựa chọn thay thế dựa trên những lựa chọn nào phù hợp với nhu cầu của bạn nhất.

CHỈNH SỬA: Một giải pháp khả thi có thể là chỉ cần sử dụng ApplicationConversionServicelớp mà Spring Boot cung cấp sẵn. Tôi thiết lập một ví dụ làm việc trên GitHub nếu bạn muốn xem giải pháp của tôi và quan trọng hơn là các giả định của tôi về dự án của bạn. Lưu ý rằng tôi đang sử dụng các java.sql.*lớp trong dự án ví dụ của mình vì ApplicationConversionServicedường như các lớp hoạt động tốt với những lớp đó.

@Bean
FieldSetMapper<User> fieldSetMapper() {
    BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
    fieldSetMapper.setTargetType(User.class);
    fieldSetMapper.setConversionService(ApplicationConversionService.getSharedInstance());
    return fieldSetMapper;
}