All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.siegmar.fastcsv.reader.AbstractCsvCallbackHandler Maven / Gradle / Ivy

Go to download

Lightning-fast, dependency-free CSV library that conforms to RFC standards.

The newest version!
package de.siegmar.fastcsv.reader;

import java.util.Objects;

import de.siegmar.fastcsv.util.Limits;

/**
 * Abstract base class for {@link CsvCallbackHandler} implementations.
 * 

* This implementation is stateful and must not be reused. * * @param the type of the resulting records */ abstract class AbstractCsvCallbackHandler extends CsvCallbackHandler { private static final int INITIAL_FIELDS_SIZE = 32; /** * The field modifier. */ protected final FieldModifier fieldModifier; /** * The starting line number of the current record. *

* See {@link CsvCallbackHandler#beginRecord(long)} and {@link CsvRecord#getStartingLineNumber()}. */ protected long startingLineNumber; /** * The internal fields array. */ protected String[] fields; /** * The total size (sum of all characters) of the current record. */ protected int recordSize; /** * The current index in the internal fields array. */ protected int fieldIdx; /** * Whether the current record is a comment. */ protected boolean comment; /** * Whether the line is empty. */ protected boolean emptyLine; /** * Constructs a new instance with an initial fields array of size {@value #INITIAL_FIELDS_SIZE}. */ protected AbstractCsvCallbackHandler() { this(FieldModifiers.NOP, INITIAL_FIELDS_SIZE); } /** * Constructs a new instance with the given field modifier and initial fields array of size * {@value #INITIAL_FIELDS_SIZE}. * * @param fieldModifier the field modifier, must not be {@code null} * @throws NullPointerException if {@code null} is passed */ protected AbstractCsvCallbackHandler(final FieldModifier fieldModifier) { this(fieldModifier, INITIAL_FIELDS_SIZE); } AbstractCsvCallbackHandler(final FieldModifier fieldModifier, final int len) { this.fieldModifier = Objects.requireNonNull(fieldModifier, "fieldModifier must not be null"); fields = new String[len]; } /** * {@inheritDoc} * Resets the internal state of this handler. */ @SuppressWarnings("checkstyle:HiddenField") @Override protected void beginRecord(final long startingLineNumber) { this.startingLineNumber = startingLineNumber; fieldIdx = 0; recordSize = 0; comment = false; emptyLine = true; } /** * {@inheritDoc} * Passes the materialized ({@link #materializeField(char[], int, int)}) and * modified ({@link #modifyField(String, boolean)}) value to {@link #addField(String, boolean)}. * * @throws CsvParseException if the addition exceeds the limit of record size or maximum fields count. */ @Override protected void addField(final char[] buf, final int offset, final int len, final boolean quoted) { if (recordSize + len > Limits.MAX_RECORD_SIZE) { throw new CsvParseException(maxRecordSizeExceededMessage(startingLineNumber)); } emptyLine = emptyLine && fieldIdx == 0 && len == 0 && !quoted; addField(modifyField(materializeField(buf, offset, len), quoted), quoted); } /** * Adds the given value to the internal fields array. *

* Extends the array if necessary and keeps track of the total record size and fields count. * * @param value the field value * @param quoted {@code true} if the field was quoted * @throws CsvParseException if the addition exceeds the maximum fields count. */ protected void addField(final String value, final boolean quoted) { if (fieldIdx == fields.length) { extendCapacity(); } fields[fieldIdx++] = value; recordSize += value.length(); } /** * Modifies field value. * * @param value the field value * @param quoted {@code true} if the field was quoted * @return the modified field value */ protected String modifyField(final String value, final boolean quoted) { return fieldModifier.modify(startingLineNumber, fieldIdx, quoted, value); } /** * Materializes field from the given buffer. * * @param buf the internal buffer that contains the field value (among other data) * @param offset the offset of the field value in the buffer * @param len the length of the field value * @return the materialized field value */ protected String materializeField(final char[] buf, final int offset, final int len) { return new String(buf, offset, len); } private static String maxRecordSizeExceededMessage(final long line) { return String.format("Record starting at line %d has surpassed the maximum limit of %d characters", line, Limits.MAX_RECORD_SIZE); } /** * {@inheritDoc} * Passes the materialized ({@link #materializeComment(char[], int, int)}) and * modified ({@link #modifyComment(String)}) value to {@link #setComment(String)}. * * @throws CsvParseException if the addition exceeds the limit of record size. */ @Override protected void setComment(final char[] buf, final int offset, final int len) { if (fieldIdx != 0) { // Can't happen with the current implementation of CsvParser throw new IllegalStateException("Comment must be the first and only field in a record"); } if (recordSize + len > Limits.MAX_RECORD_SIZE) { // Can't happen with the current implementation of CsvParser throw new CsvParseException(maxRecordSizeExceededMessage(startingLineNumber)); } setComment(modifyComment(materializeComment(buf, offset, len))); } /** * Sets the given value as the only field in the internal fields array. *

* Keeps track of the total record size. * * @param value the comment value * @throws CsvParseException if the addition exceeds the limit of record size. */ protected void setComment(final String value) { comment = true; emptyLine = false; recordSize += value.length(); fields[fieldIdx++] = value; } /** * Modifies comment value. * * @param field the comment value * @return the modified comment value */ protected String modifyComment(final String field) { return fieldModifier.modifyComment(startingLineNumber, field); } /** * Materializes comment from the given buffer. * * @param buf the internal buffer that contains the comment value (among other data) * @param offset the offset of the field value in the buffer * @param len the length of the field value * @return the materialized field value */ protected String materializeComment(final char[] buf, final int offset, final int len) { return new String(buf, offset, len); } private void extendCapacity() { final int newLen = fields.length * 2; if (newLen > Limits.MAX_FIELD_COUNT) { throw new CsvParseException("Maximum number of fields exceeded: " + Limits.MAX_FIELD_COUNT); } final String[] newFields = new String[newLen]; System.arraycopy(fields, 0, newFields, 0, fieldIdx); fields = newFields; } /** * Builds a compact fields array (a copy of the internal fields array with the length of the current record). *

* In contrast to the class property {@link #fields}, the returned array does only contain the fields of the * current record. * * @return the compact fields array */ protected String[] compactFields() { final String[] ret = new String[fieldIdx]; System.arraycopy(fields, 0, ret, 0, fieldIdx); return ret; } /** * Builds a record wrapper for the given record. * * @param rec the record, must not be {@code null} * @return the record wrapper * @throws NullPointerException if {@code rec} is {@code null} */ protected RecordWrapper buildWrapper(final T rec) { return new RecordWrapper<>(comment, emptyLine, fieldIdx, rec); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy