From 0111095657200e13ce3c0d5964eaee7de9b12858 Mon Sep 17 00:00:00 2001 From: ahaa Date: Tue, 15 Oct 2013 11:17:13 +0200 Subject: [PATCH] CAMEL-6381: Add option to tell bindy that the last field is till end of line --- .../dataformat/bindy/BindyCsvFactory.java | 177 ++++++++++-------- .../bindy/annotation/CsvRecord.java | 5 + .../bindy/csv/BindyCsvDataFormat.java | 115 ++++++++---- .../csv/BindySimpleCsvAutospanLineTest.java | 83 ++++++++ .../simple/spanLastRecord/SpanLastRecord.java | 40 ++++ 5 files changed, 306 insertions(+), 114 deletions(-) create mode 100644 components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvAutospanLineTest.java create mode 100644 components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/simple/spanLastRecord/SpanLastRecord.java diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java index 75fd63a232e90..97e5d7c221c09 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.java @@ -53,13 +53,14 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor boolean isOneToMany; - private Map dataFields = new LinkedHashMap(); - private Map annotatedFields = new LinkedHashMap(); - private Map sections = new HashMap(); + private final Map dataFields = new LinkedHashMap(); + private final Map annotatedFields = new LinkedHashMap(); + private final Map sections = new HashMap(); private int numberOptionalFields; private int numberMandatoryFields; private int totalFields; + private int maxpos; private String separator; private boolean skipFirstLine; @@ -67,15 +68,16 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor private boolean messageOrdered; private String quote; private boolean quoting; + private boolean autospanLine; - public BindyCsvFactory(PackageScanClassResolver resolver, String... packageNames) throws Exception { + public BindyCsvFactory(final PackageScanClassResolver resolver, final String... packageNames) throws Exception { super(resolver, packageNames); // initialize specific parameters of the csv model initCsvModel(); } - public BindyCsvFactory(PackageScanClassResolver resolver, Class type) throws Exception { + public BindyCsvFactory(final PackageScanClassResolver resolver, final Class type) throws Exception { super(resolver, type); // initialize specific parameters of the csv model @@ -87,7 +89,7 @@ public BindyCsvFactory(PackageScanClassResolver resolver, Class type) throws * bind the data. This process will scan for classes according to the * package name provided, check the annotated classes and fields and * retrieve the separator of the CSV record - * + * * @throws Exception */ public void initCsvModel() throws Exception { @@ -100,18 +102,19 @@ public void initCsvModel() throws Exception { initCsvRecordParameters(); } - public void initAnnotatedFields() { + @Override + public void initAnnotatedFields() { - int maxpos = 0; - for (Class cl : models) { - List linkFields = new ArrayList(); + maxpos = 0; + for (final Class cl : models) { + final List linkFields = new ArrayList(); if (LOG.isDebugEnabled()) { LOG.debug("Class retrieved: {}", cl.getName()); } - for (Field field : cl.getDeclaredFields()) { - DataField dataField = field.getAnnotation(DataField.class); + for (final Field field : cl.getDeclaredFields()) { + final DataField dataField = field.getAnnotation(DataField.class); if (dataField != null) { if (LOG.isDebugEnabled()) { LOG.debug("Position defined in the class: {}, position: {}, Field: {}", @@ -124,9 +127,9 @@ public void initAnnotatedFields() { ++numberOptionalFields; } - int pos = dataField.pos(); + final int pos = dataField.pos(); if (annotatedFields.containsKey(pos)) { - Field f = annotatedFields.get(pos); + final Field f = annotatedFields.get(pos); LOG.warn("Potentially invalid model: existing @DataField '{}' replaced by '{}'", f.getName(), field.getName()); } dataFields.put(pos, dataField); @@ -134,7 +137,7 @@ public void initAnnotatedFields() { maxpos = Math.max(maxpos, pos); } - Link linkField = field.getAnnotation(Link.class); + final Link linkField = field.getAnnotation(Link.class); if (linkField != null) { if (LOG.isDebugEnabled()) { @@ -162,7 +165,8 @@ public void initAnnotatedFields() { } } - public void bind(List tokens, Map model, int line) throws Exception { + @Override + public void bind(final List tokens, final Map model, final int line) throws Exception { int pos = 1; int counterMandatoryFields = 0; @@ -170,13 +174,13 @@ public void bind(List tokens, Map model, int line) throw for (String data : tokens) { // Get DataField from model - DataField dataField = dataFields.get(pos); + final DataField dataField = dataFields.get(pos); ObjectHelper.notNull(dataField, "No position " + pos + " defined for the field: " + data + ", line: " + line); if (dataField.trim()) { data = data.trim(); } - + if (dataField.required()) { // Increment counter of mandatory fields ++counterMandatoryFields; @@ -189,7 +193,7 @@ public void bind(List tokens, Map model, int line) throw } // Get Field to be setted - Field field = annotatedFields.get(pos); + final Field field = annotatedFields.get(pos); field.setAccessible(true); if (LOG.isDebugEnabled()) { @@ -197,10 +201,10 @@ public void bind(List tokens, Map model, int line) throw } // Create format object to format the field - Format format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); + final Format format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); // field object to be set - Object modelField = model.get(field.getDeclaringClass().getName()); + final Object modelField = model.get(field.getDeclaringClass().getName()); // format the data received Object value = null; @@ -208,9 +212,9 @@ public void bind(List tokens, Map model, int line) throw if (!data.equals("")) { try { value = format.parse(data); - } catch (FormatException ie) { + } catch (final FormatException ie) { throw new IllegalArgumentException(ie.getMessage() + ", position: " + pos + ", line: " + line, ie); - } catch (Exception e) { + } catch (final Exception e) { throw new IllegalArgumentException("Parsing error detected for field defined at the position: " + pos + ", line: " + line, e); } } else { @@ -239,24 +243,25 @@ public void bind(List tokens, Map model, int line) throw } - public String unbind(Map model) throws Exception { + @Override + public String unbind(final Map model) throws Exception { - StringBuilder buffer = new StringBuilder(); - Map> results = new HashMap>(); + final StringBuilder buffer = new StringBuilder(); + final Map> results = new HashMap>(); // Check if separator exists ObjectHelper.notNull(this.separator, "The separator has not been instantiated or property not defined in the @CsvRecord annotation"); - char separator = ConverterUtils.getCharDelimiter(this.getSeparator()); + final char separator = ConverterUtils.getCharDelimiter(this.getSeparator()); if (LOG.isDebugEnabled()) { LOG.debug("Separator converted: '0x{}', from: {}", Integer.toHexString(separator), this.getSeparator()); } - for (Class clazz : models) { + for (final Class clazz : models) { if (model.containsKey(clazz.getName())) { - Object obj = model.get(clazz.getName()); + final Object obj = model.get(clazz.getName()); if (LOG.isDebugEnabled()) { LOG.debug("Model object: {}, class: {}", obj, obj.getClass().getName()); } @@ -275,16 +280,16 @@ public String unbind(Map model) throws Exception { l = product(results); } else { // Convert Map into List - TreeMap> sortValues = new TreeMap>(results); - List temp = new ArrayList(); + final TreeMap> sortValues = new TreeMap>(results); + final List temp = new ArrayList(); - for (Entry> entry : sortValues.entrySet()) { + for (final Entry> entry : sortValues.entrySet()) { // Get list of values - List val = entry.getValue(); + final List val = entry.getValue(); // For one to one relation // There is only one item in the list - String value = val.get(0); + final String value = val.get(0); // Add the value to the temp array if (value != null) { @@ -298,13 +303,13 @@ public String unbind(Map model) throws Exception { } if (l != null) { - Iterator> it = l.iterator(); + final Iterator> it = l.iterator(); while (it.hasNext()) { - List tokens = it.next(); - Iterator itx = tokens.iterator(); + final List tokens = it.next(); + final Iterator itx = tokens.iterator(); while (itx.hasNext()) { - String res = itx.next(); + final String res = itx.next(); if (res != null) { // the field may be enclosed in quotes if a quote was configured if (quoting && quote != null) { @@ -330,20 +335,20 @@ public String unbind(Map model) throws Exception { return buffer.toString(); } - private List> product(Map> values) { - TreeMap> sortValues = new TreeMap>(values); + private List> product(final Map> values) { + final TreeMap> sortValues = new TreeMap>(values); - List> product = new ArrayList>(); - Map index = new HashMap(); + final List> product = new ArrayList>(); + final Map index = new HashMap(); int idx = 0; int idxSize = 0; do { idxSize = 0; - List v = new ArrayList(); + final List v = new ArrayList(); for (int ii = 1; ii <= sortValues.lastKey(); ii++) { - List l = values.get(ii); + final List l = values.get(ii); if (l == null) { v.add(""); ++idxSize; @@ -377,34 +382,34 @@ private List> product(Map> values) { } /** - * + * * Generate a table containing the data formatted and sorted with their position/offset * If the model is Ordered than a key is created combining the annotation @Section and Position of the field * If a relation @OneToMany is defined, than we iterate recursively through this function * The result is placed in the Map results */ - private void generateCsvPositionMap(Class clazz, Object obj, Map> results) throws Exception { + private void generateCsvPositionMap(final Class clazz, final Object obj, final Map> results) throws Exception { String result = ""; - for (Field field : clazz.getDeclaredFields()) { + for (final Field field : clazz.getDeclaredFields()) { field.setAccessible(true); - DataField datafield = field.getAnnotation(DataField.class); + final DataField datafield = field.getAnnotation(DataField.class); if (datafield != null) { if (obj != null) { // Retrieve the format, pattern and precision associated to the type - Class type = field.getType(); + final Class type = field.getType(); // Create format - Format format = FormatFactory.getFormat(type, getLocale(), datafield); + final Format format = FormatFactory.getFormat(type, getLocale(), datafield); // Get field value - Object value = field.get(obj); + final Object value = field.get(obj); result = formatString(format, value); @@ -430,9 +435,9 @@ private void generateCsvPositionMap(Class clazz, Object obj, Map clazz, Object obj, Map list = new LinkedList(); + final List list = new LinkedList(); list.add(result); results.put(key, list); } else { - List list = results.get(key); + final List list = results.get(key); list.add(result); } } - OneToMany oneToMany = field.getAnnotation(OneToMany.class); + final OneToMany oneToMany = field.getAnnotation(OneToMany.class); if (oneToMany != null) { // Set global variable // Will be used during generation of CSV isOneToMany = true; - List list = (List)field.get(obj); + final List list = (List)field.get(obj); if (list != null) { - Iterator it = list.iterator(); + final Iterator it = list.iterator(); while (it.hasNext()) { - Object target = it.next(); + final Object target = it.next(); generateCsvPositionMap(target.getClass(), target, results); } @@ -482,25 +487,25 @@ private void generateCsvPositionMap(Class clazz, Object obj, Map dataFieldsSorted = new TreeMap(dataFields); - Iterator it = dataFieldsSorted.keySet().iterator(); + final Map dataFieldsSorted = new TreeMap(dataFields); + final Iterator it = dataFieldsSorted.keySet().iterator(); - StringBuilder builderHeader = new StringBuilder(); + final StringBuilder builderHeader = new StringBuilder(); while (it.hasNext()) { - DataField dataField = dataFieldsSorted.get(it.next()); + final DataField dataField = dataFieldsSorted.get(it.next()); // Retrieve the field - Field field = annotatedFields.get(dataField.pos()); + final Field field = annotatedFields.get(dataField.pos()); // Change accessibility to allow to read protected/private fields field.setAccessible(true); @@ -525,13 +530,13 @@ public String generateHeader() { */ private void initCsvRecordParameters() { if (separator == null) { - for (Class cl : models) { + for (final Class cl : models) { // Get annotation @CsvRecord from the class - CsvRecord record = cl.getAnnotation(CsvRecord.class); + final CsvRecord record = cl.getAnnotation(CsvRecord.class); // Get annotation @Section from the class - Section section = cl.getAnnotation(Section.class); + final Section section = cl.getAnnotation(Section.class); if (record != null) { LOG.debug("Csv record: {}", record); @@ -564,6 +569,9 @@ private void initCsvRecordParameters() { quoting = record.quoting(); LOG.debug("CSV will be quoted: {}", messageOrdered); + + autospanLine = record.autospanLine(); + LOG.debug("Autospan line in last record: {}", autospanLine); } if (section != null) { @@ -586,13 +594,13 @@ private void setDefaultValuesForFields(final Map model) throws I Exception { // Set the default values, if defined for (int i = 1; i <= dataFields.size(); i++) { - Field field = annotatedFields.get(i); + final Field field = annotatedFields.get(i); field.setAccessible(true); - DataField dataField = dataFields.get(i); - Object modelField = model.get(field.getDeclaringClass().getName()); + final DataField dataField = dataFields.get(i); + final Object modelField = model.get(field.getDeclaringClass().getName()); if (field.get(modelField) == null && !dataField.defaultValue().isEmpty()) { - Format format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); - Object value = format.parse(dataField.defaultValue()); + final Format format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); + final Object value = format.parse(dataField.defaultValue()); field.set(modelField, value); } } @@ -613,15 +621,26 @@ public boolean getGenerateHeaderColumnNames() { } /** - * Find the separator used to delimit the CSV fields + * Get boolean to skip first line in file or not + * + * @return boolean */ public boolean getSkipFirstLine() { return skipFirstLine; } + /** + * Get boolean if last record is to span the rest of the line + * + * @return boolean + */ + public boolean getAutospanLine() { + return autospanLine; + } + /** * Flag indicating if the message must be ordered - * + * * @return boolean */ public boolean isMessageOrdered() { @@ -631,4 +650,8 @@ public boolean isMessageOrdered() { public String getQuote() { return quote; } + + public int getMaxpos() { + return maxpos; + } } diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java index 238ec58be7c34..d6573e79f6885 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/CsvRecord.java @@ -80,4 +80,9 @@ */ boolean quoting() default false; + /** + * Last record spans rest of line (optional) + */ + boolean autospanLine() default false; + } diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java index 5e1cac9c65db1..613911e9db0f8 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java @@ -49,54 +49,55 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat { public BindyCsvDataFormat() { } - public BindyCsvDataFormat(String... packages) { + public BindyCsvDataFormat(final String... packages) { super(packages); } - public BindyCsvDataFormat(Class type) { + public BindyCsvDataFormat(final Class type) { super(type); } - @SuppressWarnings("unchecked") - public void marshal(Exchange exchange, Object body, OutputStream outputStream) throws Exception { + @Override + @SuppressWarnings("unchecked") + public void marshal(final Exchange exchange, final Object body, final OutputStream outputStream) throws Exception { - BindyCsvFactory factory = (BindyCsvFactory)getFactory(exchange.getContext().getPackageScanClassResolver()); + final BindyCsvFactory factory = (BindyCsvFactory)getFactory(exchange.getContext().getPackageScanClassResolver()); ObjectHelper.notNull(factory, "not instantiated"); // Get CRLF - byte[] bytesCRLF = ConverterUtils.getByteReturn(factory.getCarriageReturn()); + final byte[] bytesCRLF = ConverterUtils.getByteReturn(factory.getCarriageReturn()); if (factory.getGenerateHeaderColumnNames()) { - String result = factory.generateHeader(); - byte[] bytes = exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, result); + final String result = factory.generateHeader(); + final byte[] bytes = exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, result); outputStream.write(bytes); // Add a carriage return outputStream.write(bytesCRLF); } - List> models = new ArrayList>(); + final List> models = new ArrayList>(); // the body is not a prepared list of map that bindy expects so help a bit here and create one for us - Iterator it = ObjectHelper.createIterator(body); + final Iterator it = ObjectHelper.createIterator(body); while (it.hasNext()) { - Object model = it.next(); + final Object model = it.next(); if (model instanceof Map) { models.add((Map) model); } else { - String name = model.getClass().getName(); - Map row = new HashMap(1); + final String name = model.getClass().getName(); + final Map row = new HashMap(1); row.put(name, model); models.add(row); } } - for (Map model : models) { + for (final Map model : models) { - String result = factory.unbind(model); + final String result = factory.unbind(model); - byte[] bytes = exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, result); + final byte[] bytes = exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, result); outputStream.write(bytes); // Add a carriage return @@ -104,24 +105,25 @@ public void marshal(Exchange exchange, Object body, OutputStream outputStream) t } } - public Object unmarshal(Exchange exchange, InputStream inputStream) throws Exception { - BindyCsvFactory factory = (BindyCsvFactory)getFactory(exchange.getContext().getPackageScanClassResolver()); + @Override + public Object unmarshal(final Exchange exchange, final InputStream inputStream) throws Exception { + final BindyCsvFactory factory = (BindyCsvFactory)getFactory(exchange.getContext().getPackageScanClassResolver()); ObjectHelper.notNull(factory, "not instantiated"); // List of Pojos - List> models = new ArrayList>(); + final List> models = new ArrayList>(); // Pojos of the model Map model; - InputStreamReader in = new InputStreamReader(inputStream, IOHelper.getCharsetName(exchange)); + final InputStreamReader in = new InputStreamReader(inputStream, IOHelper.getCharsetName(exchange)); // Scanner is used to read big file - Scanner scanner = new Scanner(in); + final Scanner scanner = new Scanner(in); // Retrieve the separator defined to split the record - String separator = factory.getSeparator(); - String quote = factory .getQuote(); + final String separator = factory.getSeparator(); + final String quote = factory .getQuote(); ObjectHelper.notNull(separator, "The separator has not been defined in the annotation @CsvRecord or not instantiated during initModel."); int count = 0; @@ -138,7 +140,7 @@ public Object unmarshal(Exchange exchange, InputStream inputStream) throws Excep while (scanner.hasNextLine()) { // Read the line - String line = scanner.nextLine().trim(); + final String line = scanner.nextLine().trim(); if (ObjectHelper.isEmpty(line)) { // skip if line is empty @@ -150,23 +152,25 @@ public Object unmarshal(Exchange exchange, InputStream inputStream) throws Excep // Create POJO where CSV data will be stored model = factory.factory(); - + // Split the CSV record according to the separator defined in // annotated class @CSVRecord - String[] tokens = line.split(separator, -1); + final String[] tokens = line.split(separator, -1); List result = Arrays.asList(tokens); // must unquote tokens before use result = unquoteTokens(result, separator, quote); if (result.size() == 0 || result.isEmpty()) { throw new java.lang.IllegalArgumentException("No records have been defined in the CSV"); - } - - if (result.size() > 0) { - if (LOG.isDebugEnabled()) { + } else { + if (LOG.isDebugEnabled()) { LOG.debug("Size of the record splitted : {}", result.size()); } + if (factory.getAutospanLine()) { + result = autospanLine(result, factory.getMaxpos(), separator); + } + // Bind data from CSV record with model classes factory.bind(result, model, count); @@ -195,20 +199,56 @@ public Object unmarshal(Exchange exchange, InputStream inputStream) throws Excep } - /** + /** + * Concatenate "the rest of the line" as the last record. Works similar as + * if quoted + * + * @param result + * input result set + * @param maxpos + * position of maximum record + * @param separator + * csv separator char + * @return List with concatenated last record + */ + private List autospanLine(final List result, final int maxpos, final String separator) { + if (result.size() <= maxpos) { + return result; + } + + final List answer = new ArrayList(); + final StringBuilder lastRecord = new StringBuilder(); + + final Iterator it = result.iterator(); + for (int counter = 0; counter < maxpos - 1; counter++) { + answer.add(it.next()); + } + + while (it.hasNext()) { + lastRecord.append(it.next()); + if (it.hasNext()) { + lastRecord.append(separator); + } + } + answer.add(lastRecord.toString()); + + return answer; + } + + /** * Unquote the tokens, by removing leading and trailing quote chars, * as will handling fixing broken tokens which may have been split * by a separator inside a quote. */ - private List unquoteTokens(List result, String separator, String quote) { + private List unquoteTokens(final List result, final String separator, final String quote) { // a current quoted token which we assemble from the broken pieces // we need to do this as we use the split method on the String class // to split the line using regular expression, and it does not handle // if the separator char is also inside a quoted token, therefore we need // to fix this afterwards - StringBuilder current = new StringBuilder(); + final StringBuilder current = new StringBuilder(); - List answer = new ArrayList(); + final List answer = new ArrayList(); for (String s : result) { boolean startQuote = false; boolean endQuote = false; @@ -224,7 +264,7 @@ private List unquoteTokens(List result, String separator, String // are we in progress of rebuilding a broken token boolean currentInProgress = current.length() > 0; - // situation when field ending with a separator symbol. + // situation when field ending with a separator symbol. if (currentInProgress && startQuote && s.isEmpty()) { // Add separator, append current and reset it current.append(separator); @@ -232,7 +272,7 @@ private List unquoteTokens(List result, String separator, String current.setLength(0); continue; } - + // if we hit a start token then rebuild a broken token if (currentInProgress || startQuote) { // append to current if we are in the middle of a start quote @@ -266,7 +306,8 @@ private List unquoteTokens(List result, String separator, String return answer; } - protected BindyAbstractFactory createModelFactory(PackageScanClassResolver resolver) throws Exception { + @Override + protected BindyAbstractFactory createModelFactory(final PackageScanClassResolver resolver) throws Exception { if (getClassType() != null) { return new BindyCsvFactory(resolver, getClassType()); } else { diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvAutospanLineTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvAutospanLineTest.java new file mode 100644 index 0000000000000..1807ddf6f85ce --- /dev/null +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindySimpleCsvAutospanLineTest.java @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.dataformat.bindy.csv; + +import java.util.List; +import java.util.Map; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.dataformat.bindy.model.simple.spanLastRecord.SpanLastRecord; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.apache.camel.util.CastUtils; +import org.junit.Test; + +public class BindySimpleCsvAutospanLineTest extends CamelTestSupport { + + @Test + public void testUnmarshalNoNeedToSpanLine() throws Exception { + + final MockEndpoint mock = getMockEndpoint("mock:unmarshal"); + mock.expectedMessageCount(1); + + template.sendBody("direct:unmarshal", "1,hei,kommentar"); + + assertMockEndpointsSatisfied(); + + final List> rows = CastUtils.cast(mock.getReceivedExchanges().get(0).getIn().getBody(List.class)); + final SpanLastRecord order = rows.get(0).get(SpanLastRecord.class.getName()); + + assertEquals(1, order.getRecordId()); + assertEquals("hei", order.getName()); + assertEquals("kommentar", order.getComment()); + + } + + @Test + public void testUnmarshalSpanningLine() throws Exception { + + final MockEndpoint mock = getMockEndpoint("mock:unmarshal"); + mock.expectedMessageCount(1); + + template.sendBody("direct:unmarshal", "1,hei,kommentar,test,noe,hei"); + + assertMockEndpointsSatisfied(); + + final List> rows = CastUtils.cast(mock.getReceivedExchanges().get(0).getIn().getBody(List.class)); + final SpanLastRecord order = rows.get(0).get(SpanLastRecord.class.getName()); + + assertEquals(1, order.getRecordId()); + assertEquals("hei", order.getName()); + assertEquals("kommentar,test,noe,hei", order.getComment()); + + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + final BindyCsvDataFormat bindy = new BindyCsvDataFormat("org.apache.camel.dataformat.bindy.model.simple.spanLastRecord"); + + from("direct:unmarshal") + .unmarshal(bindy) + .to("mock:unmarshal"); + } + + }; + } +} diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/simple/spanLastRecord/SpanLastRecord.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/simple/spanLastRecord/SpanLastRecord.java new file mode 100644 index 0000000000000..a6d3737571ccb --- /dev/null +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/simple/spanLastRecord/SpanLastRecord.java @@ -0,0 +1,40 @@ +package org.apache.camel.dataformat.bindy.model.simple.spanLastRecord; + +import org.apache.camel.dataformat.bindy.annotation.CsvRecord; +import org.apache.camel.dataformat.bindy.annotation.DataField; + +@CsvRecord(separator=",", autospanLine=true) +public class SpanLastRecord { + + @DataField(pos=1) + private int recordId; + @DataField(pos=2) + private String name; + @DataField(pos=3) + private String comment; + public int getRecordId() { + return recordId; + } + public void setRecordId(final int recordId) { + this.recordId = recordId; + } + public String getName() { + return name; + } + public void setName(final String name) { + this.name = name; + } + public String getComment() { + return comment; + } + public void setComment(final String comment) { + this.comment = comment; + } + @Override + public String toString() { + return "SpanLastRecord [recordId=" + recordId + ", name=" + name + ", comment=" + comment + "]"; + } + + + +}