com.github.skjolber.stcsv.CsvMapper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of databinder Show documentation
Show all versions of databinder Show documentation
High-performance CSV databinding library
package com.github.skjolber.stcsv;
import java.io.Reader;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.objectweb.asm.MethodVisitor;
import com.github.skjolber.stcsv.builder.CsvBuilderException;
import com.github.skjolber.stcsv.builder.CsvMappingBuilder;
/**
*
* Dynamic CSV parser generator. Adapts the underlying implementation according
* to the first (header) line.
*
* Uses ASM to build the parsers.
*
* Thread-safe.
*/
public class CsvMapper extends AbstractCsvMapper {
protected final Map> factories = new ConcurrentHashMap<>();
public static CsvMappingBuilder builder(Class cls) {
return new CsvMappingBuilder(cls);
}
public CsvMapper(Class cls, char divider, char quoteCharacter, char escapeCharacter, List columns, boolean skipEmptyLines,
boolean skipComments, boolean skippableFieldsWithoutLinebreaks, ClassLoader classLoader, int bufferLength) {
super(cls, divider, quoteCharacter, escapeCharacter, columns, skipEmptyLines, skipComments, skippableFieldsWithoutLinebreaks, classLoader, bufferLength);
}
public CsvReader create(Reader reader) throws Exception {
// avoid multiple calls to read when locating the first line
// so read a full buffer
char[] current = new char[bufferLength + 1];
int start = 0;
int end = 0;
do {
int read = reader.read(current, start, bufferLength - start);
if(read == -1) {
return new EmptyCsvReader<>();
} else {
end += read;
}
for(int i = start; i < end; i++) {
if(current[i] == '\n') {
return create(reader, new String(current, 0, i), current, i + 1, end);
}
}
start += end;
} while(end < bufferLength);
throw new CsvException("No linebreak found in " + current.length + " characters");
}
public CsvReader create(Reader reader, String header, char[] current, int offset, int length) throws Exception {
StaticCsvMapper constructor = factories.get(header); // note: using the stringbuilder as a key does not work
if(constructor == null) {
boolean carriageReturns = header.length() > 1 && header.charAt(header.length() - 1) == '\r';
List fields = parseColumnNames(header);
constructor = buildStaticCsvMapper(carriageReturns, fields);
if(constructor == null) {
return new EmptyCsvReader<>();
}
factories.put(header, constructor);
}
return constructor.newInstance(reader, current, offset, length);
}
// TODO builder pattern
@SuppressWarnings({ "rawtypes", "unchecked" })
public StaticCsvMapper buildDefaultStaticCsvMapper(boolean carriageReturns) throws Exception {
return new DefaultStaticCsvMapper(super.createDefaultReaderClass(carriageReturns));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public StaticCsvMapper buildStaticCsvMapper(String firstLine) throws Exception {
boolean carriageReturns = firstLine.charAt(firstLine.length() - 2) == '\r';
String line;
if(carriageReturns) {
line = firstLine.substring(0, firstLine.length() - 2);
} else {
line = firstLine.substring(0, firstLine.length() - 1);
}
return new DefaultStaticCsvMapper(super.createReaderClass(carriageReturns, line));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public StaticCsvMapper buildStaticCsvMapper(boolean carriageReturns, String header) throws Exception {
return new DefaultStaticCsvMapper(super.createReaderClass(carriageReturns, header));
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public StaticCsvMapper buildStaticCsvMapper(boolean carriageReturns, List csvFileFieldNames) throws Exception {
return new DefaultStaticCsvMapper(super.createReaderClass(carriageReturns, csvFileFieldNames));
}
@Override
protected void writeTriConsumerVariable(String subClassInternalName, MethodVisitor mv) {
throw new CsvBuilderException();
}
}