Updated Branches: refs/heads/camel-2.10.x 8caf58427 -> 3d1acd606
CAMEL-6041 merged the patch into camel-2.10.x branch Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/3d1acd60 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3d1acd60 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3d1acd60 Branch: refs/heads/camel-2.10.x Commit: 3d1acd6063cd93a4bc0542b30f2b37e5065f8918 Parents: 8caf584 Author: Willem Jiang <ningji...@apache.org> Authored: Fri May 31 12:45:00 2013 +0800 Committer: Willem Jiang <ningji...@apache.org> Committed: Fri May 31 12:45:00 2013 +0800 ---------------------------------------------------------------------- .../dataformat/bindy/csv/BindyCsvDataFormat.java | 9 + .../BindyCVSFieldEndingWithSeparatorIssueTest.java | 120 +++++++++++++ .../dataformat/bindy/model/csv/MyCsvRecord.java | 130 +++++++++++++++ 3 files changed, 259 insertions(+), 0 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/3d1acd60/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/csv/BindyCsvDataFormat.java ---------------------------------------------------------------------- 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 08ec216..670fcf6 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 @@ -223,6 +223,15 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat { // are we in progress of rebuilding a broken token boolean currentInProgress = current.length() > 0; + // situation when field ending with a separator symbol. + if (currentInProgress && startQuote && s.isEmpty()) { + // Add separator, append current and reset it + current.append(separator); + answer.add(current.toString()); + 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 http://git-wip-us.apache.org/repos/asf/camel/blob/3d1acd60/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCVSFieldEndingWithSeparatorIssueTest.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCVSFieldEndingWithSeparatorIssueTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCVSFieldEndingWithSeparatorIssueTest.java new file mode 100644 index 0000000..b63614e --- /dev/null +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCVSFieldEndingWithSeparatorIssueTest.java @@ -0,0 +1,120 @@ +/** + * 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 org.apache.camel.CamelContext; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.dataformat.bindy.model.csv.MyCsvRecord; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.model.dataformat.BindyType; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Ignore; +import org.junit.Test; + +/** + * The parsing issue when field ends with separator is fixed by updating BindyCvsDataFormat.unquoteTokens(..)<br> + * See capture.png<br> + * + * The suggested update does fix only the separator at the end of field. + * !!! The separator in the beginning of the quoted field is still not handled. + * + */ +public class BindyCVSFieldEndingWithSeparatorIssueTest extends CamelTestSupport { + + @Test + public void testBindy() throws Exception { + CamelContext ctx = new DefaultCamelContext(); + ctx.addRoutes(createRoute()); // new ReconciliationRoute() + ctx.start(); + + String addressLine1 = "8506 SIX FORKS ROAD,"; + + MockEndpoint mock = ctx.getEndpoint("mock:result", MockEndpoint.class); + mock.expectedPropertyReceived("addressLine1", addressLine1); + + String csvLine = "\"PROBLEM SOLVER\",\"" + addressLine1 + + "\",\"SUITE 104\",\"RALEIGH\",\"NC\",\"27615\",\"US\""; + ProducerTemplate template = ctx.createProducerTemplate(); + template.sendBody("direct:fromCsv", csvLine.trim()); + + + mock.assertIsSatisfied(); + + // The algorithm of BindyCvsDataFormat.unquoteTokens(..) does not handle + // separator at end of a field + // addressLine1 results in the next field being appended -> '8506 SIX + // FORKS ROAD,,SUITE 104' + } + + @Test + public void testBindyMoreSeparators() throws Exception { + CamelContext ctx = new DefaultCamelContext(); + ctx.addRoutes(createRoute()); // new ReconciliationRoute() + ctx.start(); + + String addressLine1 = "8506 SIX FORKS ROAD, , ,,, ,"; + + MockEndpoint mock = ctx.getEndpoint("mock:result", MockEndpoint.class); + mock.expectedPropertyReceived("addressLine1", addressLine1); + + String csvLine = "\"PROBLEM SOLVER\",\"" + addressLine1 + + "\",\"SUITE 104\",\"RALEIGH\",\"NC\",\"27615\",\"US\""; + ProducerTemplate template = ctx.createProducerTemplate(); + template.sendBody("direct:fromCsv", csvLine.trim()); + + mock.assertIsSatisfied(); + + } + + @Test + @Ignore("This issue will be revisit when we have chance to rewrite bindy parser") + public void testBindySeparatorsAround() throws Exception { + CamelContext ctx = new DefaultCamelContext(); + ctx.addRoutes(createRoute()); // new ReconciliationRoute() + ctx.start(); + + // TODO The separator in the beginning of the quoted field is still not handled. + // We may need to convert the separators in the quote into some kind of safe code + String addressLine1 = ",8506 SIX FORKS ROAD,"; + + MockEndpoint mock = ctx.getEndpoint("mock:result", MockEndpoint.class); + mock.expectedPropertyReceived("addressLine1", addressLine1); + + String csvLine = "\"PROBLEM SOLVER\",\"" + addressLine1 + + "\",\"SUITE 104\",\"RALEIGH\",\"NC\",\"27615\",\"US\""; + ProducerTemplate template = ctx.createProducerTemplate(); + template.sendBody("direct:fromCsv", csvLine.trim()); + + mock.assertIsSatisfied(); + + } + + private RouteBuilder createRoute() { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("direct:fromCsv").unmarshal().bindy(BindyType.Csv, MyCsvRecord.class) + .setProperty("addressLine1", simple("${in.body.addressLine1}")) + .setProperty("addressLine2", simple("${in.body.addressLine2}")).log("${in.body}") + .to("mock:result"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/3d1acd60/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/csv/MyCsvRecord.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/csv/MyCsvRecord.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/csv/MyCsvRecord.java new file mode 100644 index 0000000..7308823 --- /dev/null +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/model/csv/MyCsvRecord.java @@ -0,0 +1,130 @@ +/** + * 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.model.csv; + +import java.io.Serializable; + +import org.apache.camel.dataformat.bindy.annotation.CsvRecord; +import org.apache.camel.dataformat.bindy.annotation.DataField; + +@SuppressWarnings("serial") +@CsvRecord(separator = "," , skipFirstLine = false) +public class MyCsvRecord implements Serializable { + + @DataField(pos = 1) + private String attention; + @DataField(pos = 2) + private String addressLine1; + @DataField(pos = 3) + private String addressLine2; + @DataField(pos = 4) + private String city; + @DataField(pos = 5) + private String state; + @DataField(pos = 6) + private String zip; + @DataField(pos = 7) + private String country; + @DataField(pos = 8) + private String dummy1; + @DataField(pos = 9) + private String dummy2; + + public MyCsvRecord() { + super(); + } + + public String getAttention() { + return attention; + } + + public void setAttention(String attention) { + this.attention = attention; + } + + public String getAddressLine1() { + return addressLine1; + } + + public void setAddressLine1(String addressLine1) { + this.addressLine1 = addressLine1; + } + + public String getAddressLine2() { + return addressLine2; + } + + public void setAddressLine2(String addressLine2) { + this.addressLine2 = addressLine2; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getZip() { + return zip; + } + + public void setZip(String zip) { + this.zip = zip; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } + + public String getDummy1() { + return dummy1; + } + + public void setDummy1(String dummy1) { + this.dummy1 = dummy1; + } + + public String getDummy2() { + return dummy2; + } + + public void setDummy2(String dummy2) { + this.dummy2 = dummy2; + } + + @Override + public String toString() { + return "Record [attention=" + attention + ", addressLine1=" + addressLine1 + ", addressLine2=" + + addressLine2 + ", city=" + city + ", state=" + state + ", zip=" + zip + ", country=" + + country + ", dummy1=" + dummy1 + ", dummy2=" + dummy2 + "]"; + } + +}