BAEL-3462 Univosity Parsers (#9222)
* BAEL-3462 CSV Univosity Example * Added a row processor example
This commit is contained in:
parent
832b32210c
commit
c66c60bcff
|
@ -116,6 +116,11 @@
|
||||||
<artifactId>slf4j-log4j12</artifactId>
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
<version>${slf4j.version}</version>
|
<version>${slf4j.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.univocity</groupId>
|
||||||
|
<artifactId>univocity-parsers</artifactId>
|
||||||
|
<version>${univocity.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.awaitility</groupId>
|
<groupId>org.awaitility</groupId>
|
||||||
<artifactId>awaitility</artifactId>
|
<artifactId>awaitility</artifactId>
|
||||||
|
@ -175,6 +180,7 @@
|
||||||
<assertj.version>3.6.2</assertj.version>
|
<assertj.version>3.6.2</assertj.version>
|
||||||
<slf4j.version>1.7.25</slf4j.version>
|
<slf4j.version>1.7.25</slf4j.version>
|
||||||
<awaitility.version>3.0.0</awaitility.version>
|
<awaitility.version>3.0.0</awaitility.version>
|
||||||
|
<univocity.version>2.8.4</univocity.version>
|
||||||
<renjin.version>RELEASE</renjin.version>
|
<renjin.version>RELEASE</renjin.version>
|
||||||
<rcaller.version>3.0</rcaller.version>
|
<rcaller.version>3.0</rcaller.version>
|
||||||
<rserve.version>1.8.1</rserve.version>
|
<rserve.version>1.8.1</rserve.version>
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.baeldung.univocity;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.baeldung.univocity.model.Product;
|
||||||
|
import com.univocity.parsers.common.processor.BeanWriterProcessor;
|
||||||
|
import com.univocity.parsers.csv.CsvWriter;
|
||||||
|
import com.univocity.parsers.csv.CsvWriterSettings;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthFields;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthWriter;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthWriterSettings;
|
||||||
|
import com.univocity.parsers.tsv.TsvWriter;
|
||||||
|
import com.univocity.parsers.tsv.TsvWriterSettings;
|
||||||
|
|
||||||
|
public class OutputService {
|
||||||
|
private Logger logger = LoggerFactory.getLogger(ParsingService.class);
|
||||||
|
|
||||||
|
public enum OutputType {
|
||||||
|
CSV, TSV, FIXED_WIDTH
|
||||||
|
};
|
||||||
|
|
||||||
|
public boolean writeData(List<Object[]> products, OutputType outputType, String outputPath) {
|
||||||
|
try (Writer outputWriter = new OutputStreamWriter(new FileOutputStream(new File(outputPath)), "UTF-8")) {
|
||||||
|
switch (outputType) {
|
||||||
|
case CSV: {
|
||||||
|
CsvWriter writer = new CsvWriter(outputWriter, new CsvWriterSettings());
|
||||||
|
writer.writeRowsAndClose(products);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TSV: {
|
||||||
|
TsvWriter writer = new TsvWriter(outputWriter, new TsvWriterSettings());
|
||||||
|
writer.writeRowsAndClose(products);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FIXED_WIDTH: {
|
||||||
|
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
|
||||||
|
FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths);
|
||||||
|
FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings);
|
||||||
|
writer.writeRowsAndClose(products);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
logger.warn("Invalid OutputType: " + outputType);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean writeBeanToFixedWidthFile(List<Product> products, String outputPath) {
|
||||||
|
try (Writer outputWriter = new OutputStreamWriter(new FileOutputStream(new File(outputPath)), "UTF-8")) {
|
||||||
|
BeanWriterProcessor<Product> rowProcessor = new BeanWriterProcessor<Product>(Product.class);
|
||||||
|
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
|
||||||
|
FixedWidthWriterSettings settings = new FixedWidthWriterSettings(fieldLengths);
|
||||||
|
settings.setHeaders("product_no", "description", "unit_price");
|
||||||
|
settings.setRowWriterProcessor(rowProcessor);
|
||||||
|
FixedWidthWriter writer = new FixedWidthWriter(outputWriter, settings);
|
||||||
|
writer.writeHeaders();
|
||||||
|
for (Product product : products) {
|
||||||
|
writer.processRecord(product);
|
||||||
|
}
|
||||||
|
writer.close();
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package com.baeldung.univocity;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.baeldung.univocity.model.Product;
|
||||||
|
import com.univocity.parsers.common.processor.BatchedColumnProcessor;
|
||||||
|
import com.univocity.parsers.common.processor.BeanListProcessor;
|
||||||
|
import com.univocity.parsers.csv.CsvParser;
|
||||||
|
import com.univocity.parsers.csv.CsvParserSettings;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthFields;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthParser;
|
||||||
|
import com.univocity.parsers.fixed.FixedWidthParserSettings;
|
||||||
|
|
||||||
|
public class ParsingService {
|
||||||
|
private Logger logger = LoggerFactory.getLogger(ParsingService.class);
|
||||||
|
|
||||||
|
public List<String[]> parseCsvFile(String relativePath) {
|
||||||
|
try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) {
|
||||||
|
CsvParserSettings settings = new CsvParserSettings();
|
||||||
|
settings.setMaxCharsPerColumn(100);
|
||||||
|
settings.setMaxColumns(50);
|
||||||
|
CsvParser parser = new CsvParser(settings);
|
||||||
|
List<String[]> parsedRows = parser.parseAll(inputReader);
|
||||||
|
return parsedRows;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("IOException opening file: " + relativePath + " " + e.getMessage());
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String[]> parseFixedWidthFile(String relativePath) {
|
||||||
|
try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) {
|
||||||
|
FixedWidthFields fieldLengths = new FixedWidthFields(8, 30, 10);
|
||||||
|
FixedWidthParserSettings settings = new FixedWidthParserSettings(fieldLengths);
|
||||||
|
|
||||||
|
FixedWidthParser parser = new FixedWidthParser(settings);
|
||||||
|
List<String[]> parsedRows = parser.parseAll(inputReader);
|
||||||
|
return parsedRows;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("IOException opening file: " + relativePath + " " + e.getMessage());
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Product> parseCsvFileIntoBeans(String relativePath) {
|
||||||
|
try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) {
|
||||||
|
BeanListProcessor<Product> rowProcessor = new BeanListProcessor<Product>(Product.class);
|
||||||
|
CsvParserSettings settings = new CsvParserSettings();
|
||||||
|
settings.setHeaderExtractionEnabled(true);
|
||||||
|
settings.setProcessor(rowProcessor);
|
||||||
|
CsvParser parser = new CsvParser(settings);
|
||||||
|
parser.parse(inputReader);
|
||||||
|
return rowProcessor.getBeans();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("IOException opening file: " + relativePath + " " + e.getMessage());
|
||||||
|
return new ArrayList<Product>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String[]> parseCsvFileInBatches(String relativePath) {
|
||||||
|
try (Reader inputReader = new InputStreamReader(new FileInputStream(new File(relativePath)), "UTF-8")) {
|
||||||
|
CsvParserSettings settings = new CsvParserSettings();
|
||||||
|
settings.setProcessor(new BatchedColumnProcessor(5) {
|
||||||
|
@Override
|
||||||
|
public void batchProcessed(int rowsInThisBatch) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
CsvParser parser = new CsvParser(settings);
|
||||||
|
List<String[]> parsedRows = parser.parseAll(inputReader);
|
||||||
|
return parsedRows;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("IOException opening file: " + relativePath + " " + e.getMessage());
|
||||||
|
return new ArrayList<String[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.baeldung.univocity.model;
|
||||||
|
|
||||||
|
import com.univocity.parsers.annotations.Parsed;
|
||||||
|
|
||||||
|
public class Product {
|
||||||
|
|
||||||
|
@Parsed(field = "product_no")
|
||||||
|
private String productNumber;
|
||||||
|
|
||||||
|
@Parsed
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@Parsed(field = "unit_price")
|
||||||
|
private float unitPrice;
|
||||||
|
|
||||||
|
public String getProductNumber() {
|
||||||
|
return productNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProductNumber(String productNumber) {
|
||||||
|
this.productNumber = productNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDescription(String description) {
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getUnitPrice() {
|
||||||
|
return unitPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUnitPrice(float unitPrice) {
|
||||||
|
this.unitPrice = unitPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Product [Product Number: " + productNumber + ", Description: " + description + ", Unit Price: " + unitPrice + "]";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
package com.baeldung.univocity;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.baeldung.univocity.model.Product;
|
||||||
|
|
||||||
|
public class ParsingServiceUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCsvFile_thenParsedResultsShouldBeReturned() {
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> productData = parsingService.parseCsvFile("src/test/resources/productList.csv");
|
||||||
|
assertEquals(3, productData.size());
|
||||||
|
assertEquals(3, productData.get(0).length);
|
||||||
|
assertEquals("A8993-10", productData.get(0)[0]);
|
||||||
|
assertEquals("Extra large widget", productData.get(0)[1]);
|
||||||
|
assertEquals("35.42", productData.get(0)[2]);
|
||||||
|
assertEquals("D-2938-1", productData.get(1)[0]);
|
||||||
|
assertEquals("Winding widget \"Deluxe Model\"", productData.get(1)[1]);
|
||||||
|
assertEquals("245.99", productData.get(1)[2]);
|
||||||
|
assertEquals("R3212-32", productData.get(2)[0]);
|
||||||
|
assertEquals("Standard widget", productData.get(2)[1]);
|
||||||
|
assertEquals("2.34", productData.get(2)[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenFixedWidthFile_thenParsedResultsShouldBeReturned() {
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> productData = parsingService.parseFixedWidthFile("src/test/resources/productList.txt");
|
||||||
|
// Note: any extra spaces on the end will cause a null line to be added
|
||||||
|
assertEquals(3, productData.size());
|
||||||
|
assertEquals(3, productData.get(0).length);
|
||||||
|
assertEquals("A8993-10", productData.get(0)[0]);
|
||||||
|
assertEquals("Extra large widget", productData.get(0)[1]);
|
||||||
|
assertEquals("35.42", productData.get(0)[2]);
|
||||||
|
assertEquals("D-2938-1", productData.get(1)[0]);
|
||||||
|
assertEquals("Winding widget \"Deluxe Model\"", productData.get(1)[1]);
|
||||||
|
assertEquals("245.99", productData.get(1)[2]);
|
||||||
|
assertEquals("R3212-32", productData.get(2)[0]);
|
||||||
|
assertEquals("Standard widget", productData.get(2)[1]);
|
||||||
|
assertEquals("2.34", productData.get(2)[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDataAndCsvOutputType_thenCsvFileProduced() {
|
||||||
|
OutputService outputService = new OutputService();
|
||||||
|
List<Object[]> productData = new ArrayList<>();
|
||||||
|
productData.add(new Object[] { "1000-3-0", "Widget No. 96", "5.67" });
|
||||||
|
productData.add(new Object[] { "G930-M-P", "1/4\" Wocket", ".67" });
|
||||||
|
productData.add(new Object[] { "8080-0-M", "No. 54 Jumbo Widget", "35.74" });
|
||||||
|
outputService.writeData(productData, OutputService.OutputType.CSV, "src/test/resources/outputProductList.csv");
|
||||||
|
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> writtenData = parsingService.parseCsvFile("src/test/resources/outputProductList.csv");
|
||||||
|
assertEquals(3, writtenData.size());
|
||||||
|
assertEquals(3, writtenData.get(0).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenDataAndFixedWidthOutputType_thenFixedWidthFileProduced() {
|
||||||
|
OutputService outputService = new OutputService();
|
||||||
|
List<Object[]> productData = new ArrayList<>();
|
||||||
|
productData.add(new Object[] { "1000-3-0", "Widget No. 96", "5.67" });
|
||||||
|
productData.add(new Object[] { "G930-M-P", "1/4\" Wocket", ".67" });
|
||||||
|
productData.add(new Object[] { "8080-0-M", "No. 54 Jumbo Widget", "35.74" });
|
||||||
|
outputService.writeData(productData, OutputService.OutputType.FIXED_WIDTH, "src/test/resources/outputProductList.txt");
|
||||||
|
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> writtenData = parsingService.parseFixedWidthFile("src/test/resources/outputProductList.txt");
|
||||||
|
assertEquals(3, writtenData.size());
|
||||||
|
assertEquals(3, writtenData.get(0).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenCsvFile_thenCsvFileParsedIntoBeans() {
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<Product> products = parsingService.parseCsvFileIntoBeans("src/test/resources/productListWithHeaders.csv");
|
||||||
|
assertEquals(2, products.size());
|
||||||
|
assertEquals("Product [Product Number: 99-378AG, Description: Wocket Widget #42, Unit Price: 3.56]", products.get(0)
|
||||||
|
.toString());
|
||||||
|
assertEquals("Product [Product Number: TB-333-0, Description: Turbine Widget replacement kit, Unit Price: 800.99]", products.get(1)
|
||||||
|
.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLisOfProduct_thenWriteFixedWidthFile() {
|
||||||
|
OutputService outputService = new OutputService();
|
||||||
|
Product product = new Product();
|
||||||
|
product.setProductNumber("007-PPG0");
|
||||||
|
product.setDescription("3/8\" x 1\" Wocket");
|
||||||
|
product.setUnitPrice(45.99f);
|
||||||
|
List<Product> products = new ArrayList<>();
|
||||||
|
products.add(product);
|
||||||
|
outputService.writeBeanToFixedWidthFile(products, "src/test/resources/productListWithHeaders.txt");
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> writtenData = parsingService.parseFixedWidthFile("src/test/resources/productListWithHeaders.txt");
|
||||||
|
assertEquals(2, writtenData.size());
|
||||||
|
assertEquals(3, writtenData.get(0).length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void givenLargeCsvFile_thenParsedDataShouldBeReturned() {
|
||||||
|
ParsingService parsingService = new ParsingService();
|
||||||
|
List<String[]> productData = parsingService.parseCsvFileInBatches("src/test/resources/largeProductList.csv");
|
||||||
|
assertEquals(36, productData.size());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
A8993-10,"Extra large widget",35.42
|
||||||
|
D-2938-1,"Winding widget ""Deluxe Model""",245.99
|
||||||
|
R3212-32,"Standard widget",2.34
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
A8993-10Extra large widget 35.42
|
||||||
|
D-2938-1Winding widget "Deluxe Model" 245.99
|
||||||
|
R3212-32Standard widget 2.34
|
|
@ -0,0 +1,3 @@
|
||||||
|
product_no, description, unit_price
|
||||||
|
99-378AG,Wocket Widget #42,3.56
|
||||||
|
TB-333-0,Turbine Widget replacement kit,800.99
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
product_description unit_price
|
||||||
|
007-PPG03/8" x 1" Wocket 45.99
|
Loading…
Reference in New Issue