You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2018/02/01 08:36:57 UTC
[camel] 01/02: CAMEL-12192 support csv bindy skip fields
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 024b059663be07eea6c4379c9114e7ca6563acd9
Author: longxu <ne...@gmail.com>
AuthorDate: Tue Jan 30 22:16:43 2018 +1100
CAMEL-12192 support csv bindy skip fields
---
.../camel/dataformat/bindy/BindyCsvFactory.java | 188 ++++++++++++---------
.../dataformat/bindy/csv/BindyCsvDataFormat.java | 16 +-
.../bindy/csv/BindyCsvSkipFieldTest.java | 170 +++++++++++++++++++
.../bindy/csv/BindyCsvSkipFieldTest-context.xml | 34 ++++
4 files changed, 328 insertions(+), 80 deletions(-)
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 9906402..0015947 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
@@ -75,12 +75,20 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor
private boolean allowEmptyStream;
private boolean quotingEscaped;
private boolean endWithLineBreak;
+
+ private boolean isSkipField;
public BindyCsvFactory(Class<?> type) throws Exception {
+ this(type, false);
+ }
+
+ public BindyCsvFactory(Class<?> type, boolean isSkipField) throws Exception {
super(type);
// initialize specific parameters of the csv model
initCsvModel();
+
+ this.isSkipField = isSkipField;
}
/**
@@ -174,105 +182,118 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor
// Get DataField from model
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 a DataField can be skipped, it needs to check whether it is in dataFields keyset
+ if (isSkipField()) {
+ if (dataFields.keySet().contains(pos)) {
+ counterMandatoryFields = setDataFieldValue(camelContext, model, line, pos, counterMandatoryFields, data, dataField);
+ }
+ } else {
+ counterMandatoryFields = setDataFieldValue(camelContext, model, line, pos, counterMandatoryFields, data, dataField);
}
+
+ ++pos;
- if (dataField.required()) {
- // Increment counter of mandatory fields
- ++counterMandatoryFields;
+ }
- // Check if content of the field is empty
- // This is not possible for mandatory fields
- if (data.equals("")) {
- throw new IllegalArgumentException("The mandatory field defined at the position " + pos + " is empty for the line: " + line);
- }
- }
+ LOG.debug("Counter mandatory fields: {}", counterMandatoryFields);
- // Get Field to be setted
- Field field = annotatedFields.get(pos);
- field.setAccessible(true);
+ if (counterMandatoryFields < numberMandatoryFields) {
+ throw new IllegalArgumentException("Some mandatory fields are missing, line: " + line);
+ }
- if (LOG.isDebugEnabled()) {
- LOG.debug("Pos: {}, Data: {}, Field type: {}", new Object[]{pos, data, field.getType()});
+ if (pos < totalFields) {
+ setDefaultValuesForFields(model);
+ }
+
+ }
+
+ private int setDataFieldValue(CamelContext camelContext, Map<String, Object> model, int line, int pos, int counterMandatoryFields, String data, DataField dataField) throws Exception {
+ 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;
+
+ // Check if content of the field is empty
+ // This is not possible for mandatory fields
+ if (data.equals("")) {
+ throw new IllegalArgumentException("The mandatory field defined at the position " + pos + " is empty for the line: " + line);
}
+ }
- // Create format object to format the field
- FormattingOptions formattingOptions = ConverterUtils.convert(dataField,
- field.getType(),
- field.getAnnotation(BindyConverter.class),
- getLocale());
- Format<?> format = formatFactory.getFormat(formattingOptions);
+ // Get Field to be setted
+ Field field = annotatedFields.get(pos);
+ field.setAccessible(true);
- // field object to be set
- Object modelField = model.get(field.getDeclaringClass().getName());
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Pos: {}, Data: {}, Field type: {}", new Object[]{pos, data, field.getType()});
+ }
- // format the data received
- Object value = null;
+ // Create format object to format the field
+ FormattingOptions formattingOptions = ConverterUtils.convert(dataField,
+ field.getType(),
+ field.getAnnotation(BindyConverter.class),
+ getLocale());
+ Format<?> format = formatFactory.getFormat(formattingOptions);
- if (!data.equals("")) {
- try {
- if (quoting && quote != null && (data.contains("\\" + quote) || data.contains(quote)) && quotingEscaped) {
- value = format.parse(data.replaceAll("\\\\" + quote, "\\" + quote));
- } else {
- value = format.parse(data);
- }
- } catch (FormatException ie) {
- throw new IllegalArgumentException(ie.getMessage() + ", position: " + pos + ", line: " + line, ie);
- } catch (Exception e) {
- throw new IllegalArgumentException("Parsing error detected for field defined at the position: " + pos + ", line: " + line, e);
- }
- } else {
- if (!dataField.defaultValue().isEmpty()) {
- value = format.parse(dataField.defaultValue());
+ // field object to be set
+ Object modelField = model.get(field.getDeclaringClass().getName());
+
+ // format the data received
+ Object value = null;
+
+ if (!data.equals("")) {
+ try {
+ if (quoting && quote != null && (data.contains("\\" + quote) || data.contains(quote)) && quotingEscaped) {
+ value = format.parse(data.replaceAll("\\\\" + quote, "\\" + quote));
} else {
- value = getDefaultValueForPrimitive(field.getType());
+ value = format.parse(data);
}
+ } catch (FormatException ie) {
+ throw new IllegalArgumentException(ie.getMessage() + ", position: " + pos + ", line: " + line, ie);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Parsing error detected for field defined at the position: " + pos + ", line: " + line, e);
}
-
- if (value != null && !dataField.method().isEmpty()) {
- Class<?> clazz;
- if (dataField.method().contains(".")) {
- clazz = camelContext.getClassResolver().resolveMandatoryClass(dataField.method().substring(0, dataField.method().lastIndexOf(".")));
- } else {
- clazz = field.getType();
- }
-
- String methodName = dataField.method().substring(dataField.method().lastIndexOf(".") + 1,
- dataField.method().length());
-
- Method m = ReflectionHelper.findMethod(clazz, methodName, field.getType());
- if (m != null) {
- // this method must be static and return type
- // must be the same as the datafield and
- // must receive only the datafield value
- // as the method argument
- value = ObjectHelper.invokeMethod(m, null, value);
- } else {
- // fallback to method without parameter, that is on the value itself
- m = ReflectionHelper.findMethod(clazz, methodName);
- value = ObjectHelper.invokeMethod(m, value);
- }
+ } else {
+ if (!dataField.defaultValue().isEmpty()) {
+ value = format.parse(dataField.defaultValue());
+ } else {
+ value = getDefaultValueForPrimitive(field.getType());
}
-
- field.set(modelField, value);
-
- ++pos;
-
}
- LOG.debug("Counter mandatory fields: {}", counterMandatoryFields);
+ if (value != null && !dataField.method().isEmpty()) {
+ Class<?> clazz;
+ if (dataField.method().contains(".")) {
+ clazz = camelContext.getClassResolver().resolveMandatoryClass(dataField.method().substring(0, dataField.method().lastIndexOf(".")));
+ } else {
+ clazz = field.getType();
+ }
- if (counterMandatoryFields < numberMandatoryFields) {
- throw new IllegalArgumentException("Some mandatory fields are missing, line: " + line);
- }
+ String methodName = dataField.method().substring(dataField.method().lastIndexOf(".") + 1,
+ dataField.method().length());
- if (pos < totalFields) {
- setDefaultValuesForFields(model);
+ Method m = ReflectionHelper.findMethod(clazz, methodName, field.getType());
+ if (m != null) {
+ // this method must be static and return type
+ // must be the same as the datafield and
+ // must receive only the datafield value
+ // as the method argument
+ value = ObjectHelper.invokeMethod(m, null, value);
+ } else {
+ // fallback to method without parameter, that is on the value itself
+ m = ReflectionHelper.findMethod(clazz, methodName);
+ value = ObjectHelper.invokeMethod(m, value);
+ }
}
+ field.set(modelField, value);
+ return counterMandatoryFields;
}
@Override
@@ -719,4 +740,13 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor
public boolean isEndWithLineBreak() {
return endWithLineBreak;
}
+
+ /**
+ * Indicate if DataField can be ignored
+ *
+ * @return boolean
+ */
+ public boolean isSkipField() {
+ return this.isSkipField;
+ }
}
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 00ea809..d076198 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
@@ -47,11 +47,21 @@ import org.slf4j.LoggerFactory;
public class BindyCsvDataFormat extends BindyAbstractDataFormat {
private static final Logger LOG = LoggerFactory.getLogger(BindyCsvDataFormat.class);
+ /**
+ * If isSkipField = true, a CSV file doesn't need to declare all the fields, otherwise, all the fields are mandatory.
+ */
+ private boolean isSkipField;
+
public BindyCsvDataFormat() {
}
public BindyCsvDataFormat(Class<?> type) {
+ this(type, false);
+ }
+
+ public BindyCsvDataFormat(Class<?> type, boolean isSkipField) {
super(type);
+ this.isSkipField = isSkipField;
}
@Override
@@ -310,8 +320,12 @@ public class BindyCsvDataFormat extends BindyAbstractDataFormat {
@Override
protected BindyAbstractFactory createModelFactory(FormatFactory formatFactory) throws Exception {
- BindyCsvFactory bindyCsvFactory = new BindyCsvFactory(getClassType());
+ BindyCsvFactory bindyCsvFactory = new BindyCsvFactory(getClassType(), isSkipField());
bindyCsvFactory.setFormatFactory(formatFactory);
return bindyCsvFactory;
}
+
+ private boolean isSkipField() {
+ return this.isSkipField;
+ }
}
diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest.java
new file mode 100644
index 0000000..f9907b5
--- /dev/null
+++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest.java
@@ -0,0 +1,170 @@
+/**
+ * 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.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.dataformat.bindy.annotation.CsvRecord;
+import org.apache.camel.dataformat.bindy.annotation.DataField;
+import org.junit.Test;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+
+
+@ContextConfiguration
+public class BindyCsvSkipFieldTest extends AbstractJUnit4SpringContextTests {
+
+ private static final String URI_MOCK_RESULT = "mock:result";
+ private static final String URI_DIRECT_START = "direct:start";
+
+ private static String input = "VOA,12 abc street,Skip Street,Melbourne,VIC,3000,Australia,Skip dummy1,end of record";
+
+ @Produce(uri = URI_DIRECT_START)
+ private ProducerTemplate template;
+
+ @EndpointInject(uri = URI_MOCK_RESULT)
+ private MockEndpoint result;
+
+ private String expected;
+
+ @Test
+ @DirtiesContext
+ public void testUnMarshalAndMarshal() throws Exception {
+
+ template.sendBody(input);
+ result.expectedMessageCount(1);
+ result.assertIsSatisfied();
+ }
+
+ public static class ContextConfig extends RouteBuilder {
+ BindyCsvDataFormat camelDataFormat = new BindyCsvDataFormat(CsvSkipField.class, true);
+
+ public void configure() {
+ from(URI_DIRECT_START).unmarshal(camelDataFormat)
+ .process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ CsvSkipField csvSkipField = (CsvSkipField) exchange.getIn().getBody();
+ assert csvSkipField.getAttention().equals("VOA");
+ assert csvSkipField.getAddressLine1().equals("12 abc street");
+ assert csvSkipField.getCity().equals("Melbourne");
+ assert csvSkipField.getState().equals("VIC");
+ assert csvSkipField.getZip().equals("3000");
+ assert csvSkipField.getCountry() .equals("Australia");
+ assert csvSkipField.getDummy2().equals("end of record");
+ }
+ })
+
+ .marshal(camelDataFormat)
+ .convertBodyTo(String.class)
+ .to(URI_MOCK_RESULT);
+ }
+
+ }
+
+ @CsvRecord(separator = ",")
+ public static class CsvSkipField {
+ @DataField(pos = 1)
+ private String attention;
+
+ @DataField(pos = 2)
+ private String addressLine1;
+
+ @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 = 9)
+ private String dummy2;
+
+ 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 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 getDummy2() {
+ return dummy2;
+ }
+
+ public void setDummy2(String dummy2) {
+ this.dummy2 = dummy2;
+ }
+
+ @Override
+ public String toString() {
+ return "Record [attention=" + getAttention() + ", addressLine1=" + getAddressLine1() + ", " + "city=" + getCity() + ", state=" + getState() + ", zip=" + getZip() + ", country="
+ + getCountry() + ", dummy2=" + getDummy2() + "]";
+ }
+ }
+}
diff --git a/components/camel-bindy/src/test/resources/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest-context.xml b/components/camel-bindy/src/test/resources/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest-context.xml
new file mode 100644
index 0000000..c1c6ebd
--- /dev/null
+++ b/components/camel-bindy/src/test/resources/org/apache/camel/dataformat/bindy/csv/BindyCsvSkipFieldTest-context.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring
+ http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <camelContext xmlns="http://camel.apache.org/schema/spring">
+ <routeBuilder ref="myBuilder" />
+ </camelContext>
+
+ <bean id="myBuilder" class="org.apache.camel.dataformat.bindy.csv.BindyCsvSkipFieldTest$ContextConfig"/>
+
+</beans>
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
davsclaus@apache.org.