ไม่สามารถแปลงค่าคุณสมบัติของประเภท 'java.lang.String' เป็นประเภทที่ต้องการ 'java.sql.Date'

Oct 08 2020

ฉันได้เขียนงานชุดสปริงที่อ่าน CSV และเขียนลงในฐานข้อมูลเซิร์ฟเวอร์ SQL ไฟล์ CSV มีฟิลด์บางประเภทDateและTimeStamp. ฉันใช้ FlatFileItemReader และ JdbcBatchItemWriter

รูปแบบวันที่ใน CSV ของฉันคือyyyy-MM-ddและรูปแบบ TimeStamp คือ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เพื่ออ่านจาก DB ในขั้นตอนอื่น

Reader ใน Configuration Class มีลักษณะดังนี้:

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

ในการทำงานฉันได้รับข้อผิดพลาด:

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]

ให้ข้อผิดพลาดเดียวกันสำหรับฟิลด์วันที่และเวลาอื่น ๆ ( dateOfJoiningและtimeStampReg)

แก้ไข:

ฉันแก้ไขข้อผิดพลาดสำหรับDateฟิลด์ประเภทโดยวิธีแก้ปัญหาต่อไปนี้ แต่ฉันยังคงได้รับข้อผิดพลาดเดียวกันสำหรับTimeStampฟิลด์ประเภท

ฉันสร้างcustom BeanWrapperFieldSetMapperและแทนที่มันinitBinderเพื่อเพิ่มไฟล์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);
        
    }
}

และใช้วัตถุแทนของจริงBeanWrapperFieldSetMapperในflatFileItemReaderbean โดยแทนที่ด้วย:

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

PS: แก้ไขที่กำหนดเองไม่ได้ทำงานให้และjava.sql.Date java.sql.TimeStampฉันจึงต้องเปลี่ยนไปjava.util.Dateใช้ ที่แก้ไขสำหรับDateประเภท แต่ข้อผิดพลาดยังคงมีอยู่สำหรับTimeStampประเภท

คำตอบ

2 ThomasKåsene Oct 08 2020 at 21:27

ดูเหมือนว่าแบทช์ของคุณสามารถแบ่งบรรทัดของคุณออกเป็นStringค่าได้เท่านั้น แต่ไม่สามารถแปลงประเภทที่แปลกใหม่กว่าได้ JavaDoc สำหรับBeanWrapperFieldSetMapperพูดว่า:

ในการปรับแต่งวิธีที่ค่า FieldSet จะถูกแปลงเป็นประเภทที่ต้องการสำหรับการฉีดเข้าไปในต้นแบบนั้นมีหลายทางเลือก คุณสามารถฉีดอินสแตนซ์ PropertyEditor โดยตรงผ่านคุณสมบัติ customEditors หรือคุณสามารถแทนที่เมธอด 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;
}