Fehler beim Konvertieren des Eigenschaftswerts vom Typ 'java.lang.String' in den erforderlichen Typ 'java.sql.Date'
Ich habe einen Spring-Batch-Job geschrieben, der eine CSV liest und in die SQL Server-Datenbank schreibt. Die CSV-Datei enthält einige Felder vom Typ Dateund TimeStamp. Ich verwende FlatFileItemReader und JdbcBatchItemWriter.
Das Datumsformat in meiner CSV ist JJJJ-MM- TT und das Zeitstempelformat ist JJJJ-MM-TT HH: MM: SS.SSSSSS
HINWEIS: Ich verwende java.sql.Date und TimeStamp, NICHT java.util.Date und TimeStamp
Benutzerklasse:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User{
private String firstName;
private String lastName;
private Date dateOfBirth;
private Date dateOfJoining;
private TimeStamp timeStampReg;
...
Ich verwende dieselbe Modellklasse User, um in einem anderen Schritt aus der Datenbank zu lesen.
Der Reader in der Konfigurationsklasse sieht folgendermaßen aus:
@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;
}
...
Beim Ausführen des Jobs werden folgende Fehler angezeigt:
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]
Es gibt den gleichen Fehler für andere Datums- und Zeitstempelfelder ( dateOfJoiningund timeStampReg)
BEARBEITEN:
Ich habe den Fehler für die DateTypfelder durch die folgende Lösung behoben. Es wird jedoch immer noch der gleiche Fehler für das TimeStampTypfeld angezeigt.
Ich habe ein erstellt custom BeanWrapperFieldSetMapperund es überschrieben initBinder, um ein hinzuzufügen 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);
}
}
und verwenden Sie das Objekt anstelle des tatsächlichen Objekts BeanWrapperFieldSetMapperin der flatFileItemReaderBean, indem Sie es durch Folgendes ersetzen:
MyCustomBeanWrapperFieldSetMapper<User> fieldSetMapper = new MyCustomBeanWrapperFieldSetMapper<>();
PS: Der benutzerdefinierte Editor hat für java.sql.Dateund nicht funktioniert java.sql.TimeStamp. Also musste ich umsteigen java.util.Date. Das hat es für den DateTyp behoben, aber der Fehler bleibt für den TimeStampTyp bestehen.
Antworten
Es hört sich so an, als ob Ihr Stapel nur Ihre Zeilen in StringWerte aufteilen kann , aber die exotischeren Typen nicht konvertieren kann. Das JavaDoc fürBeanWrapperFieldSetMapper sagt:
Um die Art und Weise anzupassen, in der FieldSet-Werte zum Einfügen in den Prototyp in den gewünschten Typ konvertiert werden, gibt es mehrere Möglichkeiten. Sie können PropertyEditor-Instanzen direkt über die Eigenschaft customEditors einfügen, die Methoden createBinder (Object) und initBinder (DataBinder) überschreiben oder eine benutzerdefinierte FieldSet-Implementierung bereitstellen. Sie können auch einen ConversionService verwenden, um über die Eigenschaft convertService in den gewünschten Typ zu konvertieren.
Ich schlage vor, mit einigen dieser Alternativen zu experimentieren, je nachdem, welche Ihren Anforderungen am besten entsprechen.
BEARBEITEN: Eine mögliche Lösung kann darin bestehen, einfach die ApplicationConversionServiceKlasse zu verwenden, die Spring Boot sofort bereitstellt. Ich habe ein funktionierendes Beispiel für GitHub erstellt, wenn Sie sich meine Lösung und vor allem meine Annahmen zu Ihrem Projekt ansehen möchten. Beachten Sie, dass ich die java.sql.*Klassen in meinem Beispielprojekt verwende, da dies ApplicationConversionServiceanscheinend gut funktioniert.
@Bean
FieldSetMapper<User> fieldSetMapper() {
BeanWrapperFieldSetMapper<User> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setTargetType(User.class);
fieldSetMapper.setConversionService(ApplicationConversionService.getSharedInstance());
return fieldSetMapper;
}