/* * Copyright (c) 2015 Red Hat, Inc. and/or its affiliates. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Cheng Fang - Initial API and implementation */ package org.jberet.support.io; import java.io.Serializable; import java.util.List; import java.util.Map; import javax.batch.api.BatchProperty; import javax.batch.api.chunk.ItemWriter; import javax.enterprise.context.Dependent; import javax.inject.Inject; import javax.inject.Named; import com.fasterxml.jackson.dataformat.csv.CsvGenerator; import com.fasterxml.jackson.dataformat.csv.CsvSchema; import org.jberet.support._private.SupportLogger; import org.jberet.support._private.SupportMessages; /** * An implementation of {@code javax.batch.api.chunk.ItemWriter} that writes data in CSV format using jackson-dataformat-csv. * * @see CsvItemWriter * @see JacksonCsvItemReader * @see JacksonCsvItemReaderWriterBase * @since 1.2.0 */ @Named @Dependent public class JacksonCsvItemWriter extends JacksonCsvItemReaderWriterBase implements ItemWriter { /** * Instructs this class, when the target CSV resource already exists, whether to append to, or overwrite * the existing resource, or fail. Valid values are {@code append}, {@code overwrite}, and {@code failIfExists}. * Optional property, and defaults to {@code append}. */ @Inject @BatchProperty protected String writeMode; /** * Character used to separate data rows. * Only used by generator; parser accepts three standard linefeeds ("\r", "\r\n", "\n"). * Optional protected and defaults to '\n'. * * @see "com.fasterxml.jackson.dataformat.csv.CsvSchema" */ @Inject @BatchProperty protected String lineSeparator; /** * A comma-separated list of key-value pairs that specify {@code com.fasterxml.jackson.core.JsonGenerator} features. * Optional property and defaults to null. Keys and values must be defined in * {@code com.fasterxml.jackson.core.JsonGenerator.Feature}. For example, * <p/> * <pre> * WRITE_BIGDECIMAL_AS_PLAIN=true, WRITE_NUMBERS_AS_STRINGS=true, QUOTE_NON_NUMERIC_NUMBERS=false * </pre> * * @see "com.fasterxml.jackson.core.JsonGenerator.Feature" */ @Inject @BatchProperty protected Map<String, String> jsonGeneratorFeatures; /** * A comma-separated list of key-value pairs that specify {@code com.fasterxml.jackson.dataformat.csv.CsvGenerator.Feature}. * Optional property and defaults to null. For example, * <p/> * <pre> * ALWAYS_QUOTE_STRINGS=false, STRICT_CHECK_FOR_QUOTING=true, OMIT_MISSING_TAIL_COLUMNS=false * </pre> * With the above configuration, this writer will quote string values only when necessary, * and will omit columns without matching value when they are the last values of the row. * * @see "com.fasterxml.jackson.dataformat.csv.CsvGenerator.Feature" */ @Inject @BatchProperty protected Map<String, String> csvGeneratorFeatures; /** * Fully-qualified name of a class that implements {@code com.fasterxml.jackson.core.io.OutputDecorator}, which * can be used to decorate output destinations. Typical use is to use a filter abstraction (filtered output stream, * writer) around original output destination, and apply additional processing during write operations. * Optional property and defaults to null. For example, * <p/> * <pre> * org.jberet.support.io.JsonItemReaderTest$NoopOutputDecorator * </pre> * * @see "com.fasterxml.jackson.core.io.OutputDecorator" * @see "com.fasterxml.jackson.core.JsonFactory#setOutputDecorator(com.fasterxml.jackson.core.io.OutputDecorator)" */ @Inject @BatchProperty protected Class outputDecorator; protected CsvGenerator csvGenerator; @Override public void writeItems(final List<Object> items) throws Exception { for (final Object o : items) { csvGenerator.writeObject(o); } csvGenerator.flush(); } @Override public void open(final Serializable checkpoint) throws Exception { init(); csvGenerator = (CsvGenerator) JsonItemWriter.configureJsonGenerator(jsonFactory, getOutputStream(writeMode), outputDecorator, jsonGeneratorFeatures); if (csvGeneratorFeatures != null) { for (final Map.Entry<String, String> e : csvGeneratorFeatures.entrySet()) { final String key = e.getKey(); final String value = e.getValue(); final CsvGenerator.Feature feature; try { feature = CsvGenerator.Feature.valueOf(key); } catch (final Exception e1) { throw SupportMessages.MESSAGES.unrecognizedReaderWriterProperty(key, value); } if ("true".equals(value)) { if (!feature.enabledByDefault()) { csvGenerator.configure(feature, true); } } else if ("false".equals(value)) { if (feature.enabledByDefault()) { csvGenerator.configure(feature, false); } } else { throw SupportMessages.MESSAGES.invalidReaderWriterProperty(null, value, key); } } } if (columns != null) { CsvSchema schema = buildCsvSchema(null); if (lineSeparator != null) { schema = schema.withLineSeparator(lineSeparator); } csvGenerator.setSchema(schema); } } @Override public void close() throws Exception { if (csvGenerator != null) { SupportLogger.LOGGER.closingResource(resource, this.getClass()); csvGenerator.close(); csvGenerator = null; } } @Override public Serializable checkpointInfo() throws Exception { return null; } }