Add convenience methods in FlatFileItemWriterBuilder to generate delimited files
Resolves BATCH-2696
This commit is contained in:
committed by
Michael Minella
parent
70d0e3c510
commit
e83ed1db11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,18 +15,29 @@
|
||||
*/
|
||||
package org.springframework.batch.item.file.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.springframework.batch.item.file.FlatFileFooterCallback;
|
||||
import org.springframework.batch.item.file.FlatFileHeaderCallback;
|
||||
import org.springframework.batch.item.file.FlatFileItemWriter;
|
||||
import org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor;
|
||||
import org.springframework.batch.item.file.transform.DelimitedLineAggregator;
|
||||
import org.springframework.batch.item.file.transform.FieldExtractor;
|
||||
import org.springframework.batch.item.file.transform.FormatterLineAggregator;
|
||||
import org.springframework.batch.item.file.transform.LineAggregator;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A builder implementation for the {@link FlatFileItemWriter}
|
||||
*
|
||||
* @author Michael Minella
|
||||
* @author Glenn Renfro
|
||||
* @author Mahmoud Ben Hassine
|
||||
* @since 4.0
|
||||
* @see FlatFileItemWriter
|
||||
*/
|
||||
@@ -58,6 +69,10 @@ public class FlatFileItemWriterBuilder<T> {
|
||||
|
||||
private String name;
|
||||
|
||||
private DelimitedBuilder<T> delimitedBuilder;
|
||||
|
||||
private FormattedBuilder<T> formattedBuilder;
|
||||
|
||||
/**
|
||||
* Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport}
|
||||
* should be persisted within the {@link org.springframework.batch.item.ExecutionContext}
|
||||
@@ -155,7 +170,7 @@ public class FlatFileItemWriterBuilder<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, once the step is complete, if the resource previously provdied is
|
||||
* If set to true, once the step is complete, if the resource previously provided is
|
||||
* empty, it will be deleted.
|
||||
*
|
||||
* @param shouldDelete defaults to false
|
||||
@@ -234,6 +249,236 @@ public class FlatFileItemWriterBuilder<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a {@link DelimitedBuilder} for building a
|
||||
* {@link DelimitedLineAggregator}. The {@link DelimitedLineAggregator} configured by
|
||||
* this builder will only be used if one is not explicitly configured via
|
||||
* {@link FlatFileItemWriterBuilder#lineAggregator}
|
||||
*
|
||||
* @return a {@link DelimitedBuilder}
|
||||
*
|
||||
*/
|
||||
public DelimitedBuilder<T> delimited() {
|
||||
this.delimitedBuilder = new DelimitedBuilder<>(this);
|
||||
return this.delimitedBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of a {@link FormattedBuilder} for building a
|
||||
* {@link FormatterLineAggregator}. The {@link FormatterLineAggregator} configured by
|
||||
* this builder will only be used if one is not explicitly configured via
|
||||
* {@link FlatFileItemWriterBuilder#lineAggregator}
|
||||
*
|
||||
* @return a {@link FormattedBuilder}
|
||||
*
|
||||
*/
|
||||
public FormattedBuilder<T> formatted() {
|
||||
this.formattedBuilder = new FormattedBuilder<>(this);
|
||||
return this.formattedBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for constructing a {@link FormatterLineAggregator}.
|
||||
*
|
||||
* @param <T> the type of the parent {@link FlatFileItemWriterBuilder}
|
||||
*/
|
||||
public static class FormattedBuilder<T> {
|
||||
|
||||
private FlatFileItemWriterBuilder<T> parent;
|
||||
|
||||
private String format;
|
||||
|
||||
private Locale locale = Locale.getDefault();
|
||||
|
||||
private int maximumLength = 0;
|
||||
|
||||
private int minimumLength = 0;
|
||||
|
||||
private FieldExtractor<T> fieldExtractor;
|
||||
|
||||
private List<String> names = new ArrayList<>();
|
||||
|
||||
protected FormattedBuilder(FlatFileItemWriterBuilder<T> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the format string used to aggregate items
|
||||
* @param format used to aggregate items
|
||||
* @return The instance of the builder for chaining.
|
||||
*/
|
||||
public FormattedBuilder<T> format(String format) {
|
||||
this.format = format;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the locale.
|
||||
* @param locale to use
|
||||
* @return The instance of the builder for chaining.
|
||||
*/
|
||||
public FormattedBuilder<T> locale(Locale locale) {
|
||||
this.locale = locale;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum length of the formatted string. If this is not set
|
||||
* the default is to allow any length.
|
||||
* @param minimumLength of the formatted string
|
||||
* @return The instance of the builder for chaining.
|
||||
*/
|
||||
public FormattedBuilder<T> minimumLength(int minimumLength) {
|
||||
this.minimumLength = minimumLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum length of the formatted string. If this is not set
|
||||
* the default is to allow any length.
|
||||
* @param maximumLength of the formatted string
|
||||
* @return The instance of the builder for chaining.
|
||||
*/
|
||||
public FormattedBuilder<T> maximumLength(int maximumLength) {
|
||||
this.maximumLength = maximumLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link FieldExtractor} to use to extract fields from each item.
|
||||
* @param fieldExtractor to use to extract fields from each item
|
||||
* @return The current instance of the builder
|
||||
*/
|
||||
public FlatFileItemWriterBuilder<T> fieldExtractor(FieldExtractor<T> fieldExtractor) {
|
||||
this.fieldExtractor = fieldExtractor;
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Names of each of the fields within the fields that are returned in the order
|
||||
* they occur within the formatted file. These names will be used to create
|
||||
* a {@link BeanWrapperFieldExtractor} only if no explicit field extractor
|
||||
* is set via {@link FormattedBuilder#fieldExtractor(FieldExtractor)}.
|
||||
*
|
||||
* @param names names of each field
|
||||
* @return The parent {@link FlatFileItemWriterBuilder}
|
||||
* @see BeanWrapperFieldExtractor#setNames(String[])
|
||||
*/
|
||||
public FlatFileItemWriterBuilder<T> names(String[] names) {
|
||||
this.names.addAll(Arrays.asList(names));
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public FormatterLineAggregator<T> build() {
|
||||
Assert.notNull(this.format, "A format is required");
|
||||
Assert.isTrue((this.names != null && !this.names.isEmpty()) || this.fieldExtractor != null,
|
||||
"A list of field names or a field extractor is required");
|
||||
|
||||
FormatterLineAggregator<T> formatterLineAggregator = new FormatterLineAggregator<>();
|
||||
formatterLineAggregator.setFormat(this.format);
|
||||
formatterLineAggregator.setLocale(this.locale);
|
||||
formatterLineAggregator.setMinimumLength(this.minimumLength);
|
||||
formatterLineAggregator.setMaximumLength(this.maximumLength);
|
||||
|
||||
if (this.fieldExtractor == null) {
|
||||
BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
|
||||
beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()]));
|
||||
try {
|
||||
beanWrapperFieldExtractor.afterPropertiesSet();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Unable to initialize FormatterLineAggregator", e);
|
||||
}
|
||||
this.fieldExtractor = beanWrapperFieldExtractor;
|
||||
}
|
||||
|
||||
formatterLineAggregator.setFieldExtractor(this.fieldExtractor);
|
||||
return formatterLineAggregator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for constructing a {@link DelimitedLineAggregator}
|
||||
*
|
||||
* @param <T> the type of the parent {@link FlatFileItemWriterBuilder}
|
||||
*/
|
||||
public static class DelimitedBuilder<T> {
|
||||
|
||||
private FlatFileItemWriterBuilder<T> parent;
|
||||
|
||||
private List<String> names = new ArrayList<>();
|
||||
|
||||
private String delimiter = ",";
|
||||
|
||||
private FieldExtractor<T> fieldExtractor;
|
||||
|
||||
protected DelimitedBuilder(FlatFileItemWriterBuilder<T> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the delimiter for the file.
|
||||
*
|
||||
* @param delimiter String used as a delimiter between fields.
|
||||
* @return The instance of the builder for chaining.
|
||||
* @see DelimitedLineAggregator#setDelimiter(String)
|
||||
*/
|
||||
public DelimitedBuilder<T> delimiter(String delimiter) {
|
||||
this.delimiter = delimiter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Names of each of the fields within the fields that are returned in the order
|
||||
* they occur within the delimited file. These names will be used to create
|
||||
* a {@link BeanWrapperFieldExtractor} only if no explicit field extractor
|
||||
* is set via {@link DelimitedBuilder#fieldExtractor(FieldExtractor)}.
|
||||
*
|
||||
* @param names names of each field
|
||||
* @return The parent {@link FlatFileItemWriterBuilder}
|
||||
* @see BeanWrapperFieldExtractor#setNames(String[])
|
||||
*/
|
||||
public FlatFileItemWriterBuilder<T> names(String[] names) {
|
||||
this.names.addAll(Arrays.asList(names));
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link FieldExtractor} to use to extract fields from each item.
|
||||
* @param fieldExtractor to use to extract fields from each item
|
||||
* @return The parent {@link FlatFileItemWriterBuilder}
|
||||
*/
|
||||
public FlatFileItemWriterBuilder<T> fieldExtractor(FieldExtractor<T> fieldExtractor) {
|
||||
this.fieldExtractor = fieldExtractor;
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
public DelimitedLineAggregator<T> build() {
|
||||
Assert.isTrue((this.names != null && !this.names.isEmpty()) || this.fieldExtractor != null,
|
||||
"A list of field names or a field extractor is required");
|
||||
|
||||
DelimitedLineAggregator<T> delimitedLineAggregator = new DelimitedLineAggregator<>();
|
||||
if (StringUtils.hasLength(this.delimiter)) {
|
||||
delimitedLineAggregator.setDelimiter(this.delimiter);
|
||||
}
|
||||
|
||||
if (this.fieldExtractor == null) {
|
||||
BeanWrapperFieldExtractor<T> beanWrapperFieldExtractor = new BeanWrapperFieldExtractor<>();
|
||||
beanWrapperFieldExtractor.setNames(this.names.toArray(new String[this.names.size()]));
|
||||
try {
|
||||
beanWrapperFieldExtractor.afterPropertiesSet();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException("Unable to initialize DelimitedLineAggregator", e);
|
||||
}
|
||||
this.fieldExtractor = beanWrapperFieldExtractor;
|
||||
}
|
||||
|
||||
delimitedLineAggregator.setFieldExtractor(this.fieldExtractor);
|
||||
return delimitedLineAggregator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and builds a {@link FlatFileItemWriter}.
|
||||
*
|
||||
@@ -241,7 +486,8 @@ public class FlatFileItemWriterBuilder<T> {
|
||||
*/
|
||||
public FlatFileItemWriter<T> build() {
|
||||
|
||||
Assert.notNull(this.lineAggregator, "A LineAggregator is required");
|
||||
Assert.isTrue(this.lineAggregator != null || this.delimitedBuilder != null || this.formattedBuilder != null,
|
||||
"A LineAggregator or a DelimitedBuilder or a FormattedBuilder is required");
|
||||
Assert.notNull(this.resource, "A Resource is required");
|
||||
|
||||
if(this.saveState) {
|
||||
@@ -256,6 +502,16 @@ public class FlatFileItemWriterBuilder<T> {
|
||||
writer.setFooterCallback(this.footerCallback);
|
||||
writer.setForceSync(this.forceSync);
|
||||
writer.setHeaderCallback(this.headerCallback);
|
||||
if (this.lineAggregator == null) {
|
||||
Assert.state(this.delimitedBuilder == null || this.formattedBuilder == null,
|
||||
"Either a DelimitedLineAggregator or a FormatterLineAggregator should be provided, but not both");
|
||||
if (this.delimitedBuilder != null) {
|
||||
this.lineAggregator = this.delimitedBuilder.build();
|
||||
}
|
||||
else {
|
||||
this.lineAggregator = this.formattedBuilder.build();
|
||||
}
|
||||
}
|
||||
writer.setLineAggregator(this.lineAggregator);
|
||||
writer.setLineSeparator(this.lineSeparator);
|
||||
writer.setResource(this.resource);
|
||||
|
||||
Reference in New Issue
Block a user