ไม่สามารถแปลงค่าคุณสมบัติของประเภท 'java.lang.String' เป็นประเภทที่ต้องการ 'java.sql.Date'
ฉันได้เขียนงานชุดสปริงที่อ่าน 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ประเภท
คำตอบ
ดูเหมือนว่าแบทช์ของคุณสามารถแบ่งบรรทัดของคุณออกเป็น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;
}