
org.jberet.support.io.CsvItemReader Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2013 Red Hat, Inc. and/or its affiliates.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.jberet.support.io;
import static org.jberet.support.io.CsvProperties.BEAN_TYPE_KEY;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import org.jberet.support._private.SupportLogger;
import org.jberet.support._private.SupportMessages;
import org.supercsv.io.ICsvBeanReader;
import org.supercsv.io.ICsvListReader;
import org.supercsv.io.ICsvMapReader;
import org.supercsv.io.ICsvReader;
import jakarta.batch.api.BatchProperty;
import jakarta.batch.api.chunk.ItemReader;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import jakarta.inject.Named;
/**
* An implementation of {@code jakarta.batch.api.chunk.ItemReader} that reads from a CSV resource into a user-defined
* bean, java.util.List<String>, or java.util.Map<String, String>. Data files delimited with characters
* other than comma (e.g., tab, |) are also supported by configuring {@code preference}, {@code delimiterChar},
* or {@code quoteChar} properties in job xml.
* This class is not designed to be thread-safe and its instance should not be shared between threads.
*
* @see CsvItemReaderWriterBase
* @see CsvItemWriter
* @since 1.0.0
*/
@Named
@Dependent
public class CsvItemReader extends CsvItemReaderWriterBase implements ItemReader {
/**
* Specifies the start position (a positive integer starting from 1) to read the data. If reading from the beginning
* of the input CSV, there is no need to specify this property.
*/
@Inject
@BatchProperty
protected int start;
/**
* Specify the end position in the data set (inclusive). Optional property, and defaults to {@code Integer.MAX_VALUE}.
* If reading till the end of the input CSV, there is no need to specify this property.
*/
@Inject
@BatchProperty
protected int end;
/**
* Indicates that the input CSV resource does not contain header row. Optional property, valid values are
* {@code true} or {@code false}, and the default is {@code false}.
*/
@Inject
@BatchProperty
protected boolean headerless;
protected ICsvReader delegateReader;
@Override
public void open(final Serializable checkpoint) throws Exception {
/**
* The row number to start reading. It may be different from the injected field start. During a restart,
* we would start reading from where it ended during the last run.
*/
if (this.end == 0) {
this.end = Integer.MAX_VALUE;
}
int startRowNumber = checkpoint == null ? this.start : (Integer) checkpoint;
if (startRowNumber < this.start || startRowNumber > this.end || startRowNumber < 0) {
throw SupportMessages.MESSAGES.invalidStartPosition(startRowNumber, this.start, this.end);
}
if (headerless) {
startRowNumber--;
this.end--;
}
if (beanType == null) {
throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, null, BEAN_TYPE_KEY);
}
final InputStream inputStream = getInputStream(resource, true);
final InputStreamReader r = charset == null ? new InputStreamReader(inputStream) :
new InputStreamReader(inputStream, charset);
if (java.util.List.class.isAssignableFrom(beanType)) {
delegateReader = new FastForwardCsvListReader(r, getCsvPreference(), startRowNumber);
} else if (java.util.Map.class.isAssignableFrom(beanType)) {
delegateReader = new FastForwardCsvMapReader(r, getCsvPreference(), startRowNumber);
} else {
delegateReader = new FastForwardCsvBeanReader(r, getCsvPreference(), startRowNumber);
}
SupportLogger.LOGGER.openingResource(resource, this.getClass());
if (!headerless) {
final String[] header;
try {
header = delegateReader.getHeader(true); //first line check true
} catch (final IOException e) {
throw SupportMessages.MESSAGES.failToReadCsvHeader(e, resource);
}
if (this.nameMapping == null) {
this.nameMapping = header;
}
}
this.cellProcessorInstances = getCellProcessors();
}
@Override
public void close() throws Exception {
if (delegateReader != null) {
SupportLogger.LOGGER.closingResource(resource, this.getClass());
delegateReader.close();
delegateReader = null;
}
}
@Override
public Object readItem() throws Exception {
if (delegateReader.getRowNumber() > this.end) {
return null;
}
final Object result;
if (delegateReader instanceof org.supercsv.io.ICsvBeanReader) {
if (cellProcessorInstances.length == 0) {
result = ((ICsvBeanReader) delegateReader).read(beanType, getNameMapping());
} else {
result = ((ICsvBeanReader) delegateReader).read(beanType, getNameMapping(), cellProcessorInstances);
}
if (!skipBeanValidation) {
ItemReaderWriterBase.validate(result);
}
} else if (delegateReader instanceof ICsvListReader) {
if (cellProcessorInstances.length == 0) {
result = ((ICsvListReader) delegateReader).read();
} else {
result = ((ICsvListReader) delegateReader).read(cellProcessorInstances);
}
} else {
if (cellProcessorInstances.length == 0) {
result = ((ICsvMapReader) delegateReader).read(getNameMapping());
} else {
result = ((ICsvMapReader) delegateReader).read(getNameMapping(), cellProcessorInstances);
}
}
return result;
}
@Override
public Integer checkpointInfo() throws Exception {
return delegateReader.getRowNumber();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy