Repository: camel Updated Branches: refs/heads/master 274957ad6 -> 1f9dc80da
CAMEL-6163: camel-bindy add custom data converter. Thanks to Roberto Coral Azambuja for the patch. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/1f9dc80d Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/1f9dc80d Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/1f9dc80d Branch: refs/heads/master Commit: 1f9dc80da113ea4fd29b9bde6a5fe12dc346df5d Parents: 274957a Author: Claus Ibsen <davscl...@apache.org> Authored: Tue Mar 22 16:32:54 2016 +0100 Committer: Claus Ibsen <davscl...@apache.org> Committed: Tue Mar 22 16:32:54 2016 +0100 ---------------------------------------------------------------------- .../camel/dataformat/bindy/BindyCsvFactory.java | 9 +- .../bindy/BindyFixedLengthFactory.java | 115 +++++++-------- .../bindy/BindyKeyValuePairFactory.java | 21 +-- .../camel/dataformat/bindy/FormatFactory.java | 13 +- .../bindy/annotation/BindyConverter.java | 34 +++++ .../fixed/converter/BindyConverterTest.java | 139 +++++++++++++++++++ 6 files changed, 261 insertions(+), 70 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyCsvFactory.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 a699c04..045970d 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 @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import org.apache.camel.dataformat.bindy.annotation.BindyConverter; import org.apache.camel.dataformat.bindy.annotation.CsvRecord; import org.apache.camel.dataformat.bindy.annotation.DataField; import org.apache.camel.dataformat.bindy.annotation.Link; @@ -155,6 +156,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor } } + @Override public void bind(List<String> tokens, Map<String, Object> model, int line) throws Exception { int pos = 1; @@ -190,7 +192,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor } // Create format object to format the field - Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); + Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField, field.getAnnotation(BindyConverter.class)); // field object to be set Object modelField = model.get(field.getDeclaringClass().getName()); @@ -232,6 +234,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor } + @Override public String unbind(Map<String, Object> model) throws Exception { StringBuilder buffer = new StringBuilder(); @@ -393,7 +396,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor Class<?> type = field.getType(); // Create format - Format<?> format = FormatFactory.getFormat(type, getLocale(), datafield); + Format<?> format = FormatFactory.getFormat(type, getLocale(), datafield, field.getAnnotation(BindyConverter.class)); // Get field value Object value = field.get(obj); @@ -586,7 +589,7 @@ public class BindyCsvFactory extends BindyAbstractFactory implements BindyFactor DataField dataField = dataFields.get(i); Object modelField = model.get(field.getDeclaringClass().getName()); if (field.get(modelField) == null && !dataField.defaultValue().isEmpty()) { - Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); + Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField, field.getAnnotation(BindyConverter.class)); Object value = format.parse(dataField.defaultValue()); field.set(modelField, value); } http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java index 920d9e6..d6b8aed 100644 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyFixedLengthFactory.java @@ -27,6 +27,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import org.apache.camel.dataformat.bindy.annotation.BindyConverter; import org.apache.camel.dataformat.bindy.annotation.DataField; import org.apache.camel.dataformat.bindy.annotation.FixedLengthRecord; import org.apache.camel.dataformat.bindy.annotation.Link; @@ -48,7 +49,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin private Map<Integer, DataField> dataFields = new TreeMap<Integer, DataField>(); private Map<Integer, Field> annotatedFields = new TreeMap<Integer, Field>(); - + private int numberOptionalFields; private int numberMandatoryFields; private int totalFields; @@ -62,27 +63,27 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin private char paddingChar; private int recordLength; private boolean ignoreTrailingChars; - + private Class<?> header; private Class<?> footer; public BindyFixedLengthFactory(Class<?> type) throws Exception { super(type); - + header = void.class; footer = void.class; - + // initialize specific parameters of the fixed length model initFixedLengthModel(); } - + /** * method uses to initialize the model representing the classes who will * bind the data. This process will scan for classes according to the * package name provided, check the annotated classes and fields */ - public void initFixedLengthModel() throws Exception { - + public void initFixedLengthModel() throws Exception { + // Find annotated fields declared in the Model classes initAnnotatedFields(); @@ -91,6 +92,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin initFixedLengthRecordParameters(); } + @Override public void initAnnotatedFields() { for (Class<?> cl : models) { @@ -104,7 +106,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin for (Field field : cl.getDeclaredFields()) { DataField dataField = field.getAnnotation(DataField.class); if (dataField != null) { - + if (LOG.isDebugEnabled()) { LOG.debug("Position defined in the class: {}, position: {}, Field: {}", new Object[]{cl.getName(), dataField.pos(), dataField}); } @@ -144,9 +146,9 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin } } - + // Will not be used in the case of a Fixed Length record - // as we provide the content of the record and + // as we provide the content of the record and // we don't split it as this is the case for a CSV record @Override public void bind(List<String> data, Map<String, Object> model, int line) throws Exception { @@ -175,7 +177,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin dataField = itr.next(); length = dataField.length(); delimiter = dataField.delimiter(); - + if (length == 0 && dataField.lengthPos() != 0) { Field lengthField = annotatedFields.get(dataField.lengthPos()); lengthField.setAccessible(true); @@ -196,7 +198,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin LOG.debug("skipping ahead [" + (dataField.pos() - offset) + "] chars."); offset = dataField.pos(); } - + if (length > 0) { token = record.substring(offset - 1, offset + length - 1); offset += length; @@ -227,7 +229,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin + " is empty for the line: " + line); } } - + // Get Field to be set field = annotatedFields.get(dataField.pos()); field.setAccessible(true); @@ -237,7 +239,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin } // Create format object to format the field - Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField); + Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), dataField, field.getAnnotation(BindyConverter.class)); // field object to be set Object modelField = model.get(field.getDeclaringClass().getName()); @@ -258,11 +260,11 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin } field.set(modelField, value); - + ++pos; - + } - + // check for unmapped non-whitespace data at the end of the line if (offset <= record.length() && !(record.substring(offset - 1, record.length())).trim().equals("") && !isIgnoreTrailingChars()) { throw new IllegalArgumentException("Unexpected / unmapped characters found at the end of the fixed-length record at line : " + line); @@ -276,10 +278,11 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin if (counterMandatoryFields < numberMandatoryFields) { throw new IllegalArgumentException("Some mandatory fields are missing, line: " + line); - } - + } + } + @Override public String unbind(Map<String, Object> model) throws Exception { StringBuilder buffer = new StringBuilder(); @@ -312,15 +315,15 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin // Get list of values List<String> val = entry.getValue(); String value = val.get(0); - + buffer.append(value); } - + return buffer.toString(); } /** - * + * * Generate a table containing the data formatted and sorted with their position/offset * The result is placed in the Map<Integer, List> results */ @@ -342,7 +345,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin Class<?> type = field.getType(); // Create format - Format<?> format = FormatFactory.getFormat(type, getLocale(), datafield); + Format<?> format = FormatFactory.getFormat(type, getLocale(), datafield, field.getAnnotation(BindyConverter.class)); // Get field value Object value = field.get(obj); @@ -353,19 +356,19 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin if (datafield.trim()) { result = result.trim(); } - + int fieldLength = datafield.length(); - + if (fieldLength == 0 && (datafield.lengthPos() > 0)) { List<String> resultVals = results.get(datafield.lengthPos()); fieldLength = Integer.valueOf(resultVals.get(0)); } - + if (fieldLength <= 0 && datafield.delimiter().equals("") && datafield.lengthPos() == 0) { - throw new IllegalArgumentException("Either a delimiter value or length for the field: " + throw new IllegalArgumentException("Either a delimiter value or length for the field: " + field.getName() + " is mandatory."); } - + if (!datafield.delimiter().equals("")) { result = result + datafield.delimiter(); } else { @@ -375,10 +378,10 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin char padChar; StringBuilder temp = new StringBuilder(); - + // Check if we must pad if (result.length() < fieldLength) { - + // No padding defined for the field if (padCharField == 0) { // We use the padding defined for the Record @@ -386,7 +389,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin } else { padChar = padCharField; } - + if (align.contains("R")) { temp.append(generatePaddingChars(padChar, fieldLength, result.length())); temp.append(result); @@ -397,11 +400,11 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin throw new IllegalArgumentException("Alignment for the field: " + field.getName() + " must be equal to R for RIGHT or L for LEFT"); } - + result = temp.toString(); } else if (result.length() > fieldLength) { // we are bigger than allowed - + // is clipped enabled? if so clip the field if (datafield.clip()) { result = result.substring(0, fieldLength); @@ -437,7 +440,7 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin } } - + private String generatePaddingChars(char pad, int lengthField, int lengthString) { StringBuilder buffer = new StringBuilder(); int size = lengthField - lengthString; @@ -467,28 +470,28 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin // Get header parameter header = record.header(); - LOG.debug("Header: {}", header); + LOG.debug("Header: {}", header); hasHeader = header != void.class; LOG.debug("Has Header: {}", hasHeader); - + // Get skipHeader parameter skipHeader = record.skipHeader(); LOG.debug("Skip Header: {}", skipHeader); // Get footer parameter footer = record.footer(); - LOG.debug("Footer: {}", footer); + LOG.debug("Footer: {}", footer); hasFooter = record.footer() != void.class; LOG.debug("Has Footer: {}", hasFooter); - + // Get skipFooter parameter skipFooter = record.skipFooter(); LOG.debug("Skip Footer: {}", skipFooter); - + // Get isHeader parameter isHeader = hasHeader ? cl.equals(header) : false; LOG.debug("Is Header: {}", isHeader); - + // Get isFooter parameter isFooter = hasFooter ? cl.equals(footer) : false; LOG.debug("Is Footer: {}", isFooter); @@ -506,80 +509,80 @@ public class BindyFixedLengthFactory extends BindyAbstractFactory implements Bin LOG.debug("Ignore trailing chars: {}", ignoreTrailingChars); } } - + if (hasHeader && isHeader) { throw new java.lang.IllegalArgumentException("Record can not be configured with both 'isHeader=true' and 'hasHeader=true'"); } - + if (hasFooter && isFooter) { throw new java.lang.IllegalArgumentException("Record can not be configured with both 'isFooter=true' and 'hasFooter=true'"); } - + if ((isHeader || isFooter) && (skipHeader || skipFooter)) { throw new java.lang.IllegalArgumentException( "skipHeader and/or skipFooter can not be configured on a record where 'isHeader=true' or 'isFooter=true'"); } - + } - + /** - * + * * @return */ public Class<?> header() { return header; } - + /** * Flag indicating if we have a header */ public boolean hasHeader() { return hasHeader; - } - + } + /** - * + * * @return */ public Class<?> footer() { return footer; } - + /** * Flag indicating if we have a footer */ public boolean hasFooter() { return hasFooter; } - + /** * Flag indicating whether to skip the header parsing */ public boolean skipHeader() { return skipHeader; } - + /** * Flag indicating whether to skip the footer processing */ public boolean skipFooter() { return skipFooter; } - + /** * Flag indicating whether this factory is for a header */ public boolean isHeader() { return isHeader; } - + /** * Flag indicating whether this factory is for a footer */ public boolean isFooter() { return isFooter; } - + /** * Padding char used to fill the field */ http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyKeyValuePairFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyKeyValuePairFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyKeyValuePairFactory.java index 625a415..6625be0 100644 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyKeyValuePairFactory.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/BindyKeyValuePairFactory.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import java.util.TreeMap; +import org.apache.camel.dataformat.bindy.annotation.BindyConverter; import org.apache.camel.dataformat.bindy.annotation.KeyValuePairField; import org.apache.camel.dataformat.bindy.annotation.Link; import org.apache.camel.dataformat.bindy.annotation.Message; @@ -54,7 +55,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi private String pairSeparator; private boolean messageOrdered; - + public BindyKeyValuePairFactory(Class<?> type) throws Exception { super(type); @@ -67,7 +68,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi * bind the data This process will scan for classes according to the package * name provided, check the annotated classes and fields. Next, we retrieve * the parameters required like : Pair Separator & key value pair separator - * + * * @throws Exception */ public void initKeyValuePairModel() throws Exception { @@ -80,6 +81,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi } + @Override public void initAnnotatedFields() { for (Class<?> cl : models) { @@ -277,7 +279,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi if (value != null) { // Create format object to format the field - Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), keyValuePairField); + Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), keyValuePairField, field.getAnnotation(BindyConverter.class)); // format the value of the key received result = formatField(format, value, key, line); @@ -313,7 +315,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi value = values.get(i); // Create format object to format the field - Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), keyValuePairField); + Format<?> format = FormatFactory.getFormat(field.getType(), getLocale(), keyValuePairField, field.getAnnotation(BindyConverter.class)); // format the value of the key received Object result = formatField(format, value, key, line); @@ -399,8 +401,9 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi } /** - * + * */ + @Override public String unbind(Map<String, Object> model) throws Exception { StringBuilder builder = new StringBuilder(); @@ -441,7 +444,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi // Create format @SuppressWarnings("unchecked") - Format<Object> format = (Format<Object>)FormatFactory.getFormat(type, getLocale(), keyValuePairField); + Format<Object> format = (Format<Object>)FormatFactory.getFormat(type, getLocale(), keyValuePairField, field.getAnnotation(BindyConverter.class)); // Get object to be formatted Object obj = model.get(field.getDeclaringClass().getName()); @@ -456,9 +459,9 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi // and the position of the field Integer key1 = sections.get(obj.getClass().getName()); Integer key2 = keyValuePairField.position(); - + LOG.debug("Key of the section: {}, and the field: {}", key1, key2); - + Integer keyGenerated = generateKey(key1, key2); if (LOG.isDebugEnabled()) { @@ -575,7 +578,7 @@ public class BindyKeyValuePairFactory extends BindyAbstractFactory implements Bi /** * Flag indicating if the message must be ordered - * + * * @return boolean */ public boolean isMessageOrdered() { http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/FormatFactory.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/FormatFactory.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/FormatFactory.java index 48230a1..7a63f77 100755 --- a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/FormatFactory.java +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/FormatFactory.java @@ -22,6 +22,7 @@ import java.math.BigInteger; import java.util.Date; import java.util.Locale; +import org.apache.camel.dataformat.bindy.annotation.BindyConverter; import org.apache.camel.dataformat.bindy.annotation.DataField; import org.apache.camel.dataformat.bindy.annotation.KeyValuePairField; import org.apache.camel.dataformat.bindy.format.BigDecimalFormat; @@ -128,7 +129,11 @@ public final class FormatFactory { * @return Format the formatter * @throws IllegalArgumentException if not suitable formatter is found */ - public static Format<?> getFormat(Class<?> clazz, String locale, DataField data) throws Exception { + public static Format<?> getFormat(Class<?> clazz, String locale, DataField data, BindyConverter converter) throws Exception { + if (converter != null) { + return converter.value().newInstance(); + } + String pattern = data.pattern(); String timezone = data.timezone(); int precision = data.precision(); @@ -148,7 +153,11 @@ public final class FormatFactory { * @throws IllegalArgumentException if not suitable formatter is found * TODO : Check if KeyValuePair could also use decimal/groupingSeparator/rounding for BigDecimal */ - public static Format<?> getFormat(Class<?> clazz, String locale, KeyValuePairField data) throws Exception { + public static Format<?> getFormat(Class<?> clazz, String locale, KeyValuePairField data, BindyConverter converter) throws Exception { + if (converter != null) { + return converter.value().newInstance(); + } + String pattern = data.pattern(); String timezone = data.timezone(); int precision = data.precision(); http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/BindyConverter.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/BindyConverter.java b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/BindyConverter.java new file mode 100644 index 0000000..7dfed7e --- /dev/null +++ b/components/camel-bindy/src/main/java/org/apache/camel/dataformat/bindy/annotation/BindyConverter.java @@ -0,0 +1,34 @@ +/** + * 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.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import org.apache.camel.dataformat.bindy.Format; + + +/** + * An annotation used to identify which converter class will be used to convert + * the String field to the attribute's data type. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface BindyConverter { + Class<? extends Format<?>> value(); +} http://git-wip-us.apache.org/repos/asf/camel/blob/1f9dc80d/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/converter/BindyConverterTest.java ---------------------------------------------------------------------- diff --git a/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/converter/BindyConverterTest.java b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/converter/BindyConverterTest.java new file mode 100644 index 0000000..7ff80b3 --- /dev/null +++ b/components/camel-bindy/src/test/java/org/apache/camel/dataformat/bindy/fixed/converter/BindyConverterTest.java @@ -0,0 +1,139 @@ +/** + * 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.fixed.converter; + + +import org.apache.camel.EndpointInject; +import org.apache.camel.Exchange; +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.Format; +import org.apache.camel.dataformat.bindy.annotation.BindyConverter; +import org.apache.camel.dataformat.bindy.annotation.DataField; +import org.apache.camel.dataformat.bindy.annotation.FixedLengthRecord; +import org.apache.camel.model.dataformat.BindyDataFormat; +import org.apache.camel.model.dataformat.BindyType; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; + +@ContextConfiguration +public class BindyConverterTest extends CamelTestSupport { + + public static final String URI_DIRECT_MARSHALL = "direct:marshall"; + public static final String URI_DIRECT_UNMARSHALL = "direct:unmarshall"; + public static final String URI_MOCK_MARSHALL_RESULT = "mock:marshall-result"; + public static final String URI_MOCK_UNMARSHALL_RESULT = "mock:unmarshall-result"; + + // ************************************************************************* + // + // ************************************************************************* + + @Produce(uri = URI_DIRECT_MARSHALL) + private ProducerTemplate mtemplate; + + @EndpointInject(uri = URI_MOCK_MARSHALL_RESULT) + private MockEndpoint mresult; + + @Produce(uri = URI_DIRECT_UNMARSHALL) + private ProducerTemplate utemplate; + + @EndpointInject(uri = URI_MOCK_UNMARSHALL_RESULT) + private MockEndpoint uresult; + + // ************************************************************************* + // TEST + // ************************************************************************* + + @Test + @DirtiesContext + public void testMarshall() throws Exception { + DataModel rec = new DataModel(); + rec.field1 = "0123456789"; + mresult.expectedBodiesReceived("9876543210\r\n"); + + mtemplate.sendBody(rec); + mresult.assertIsSatisfied(); + } + + @Test + @DirtiesContext + public void testUnMarshall() throws Exception { + utemplate.sendBody("9876543210\r\n"); + + uresult.expectedMessageCount(1); + uresult.assertIsSatisfied(); + + // check the model + Exchange exc = uresult.getReceivedExchanges().get(0); + DataModel data = exc.getIn().getBody(DataModel.class); + + Assert.assertEquals("0123456789", data.field1); + } + + // ************************************************************************* + // ROUTES + // ************************************************************************* + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + RouteBuilder routeBuilder = new RouteBuilder() { + @Override + public void configure() throws Exception { + BindyDataFormat bindy = new BindyDataFormat(); + bindy.setClassType(DataModel.class); + bindy.setType(BindyType.Fixed); + + from(URI_DIRECT_MARSHALL) + .marshal(bindy) + .to(URI_MOCK_MARSHALL_RESULT); + from(URI_DIRECT_UNMARSHALL) + .unmarshal().bindy(BindyType.Fixed, DataModel.class) + .to(URI_MOCK_UNMARSHALL_RESULT); + } + }; + + return routeBuilder; + } + + // ************************************************************************* + // DATA MODEL + // ************************************************************************* + + @FixedLengthRecord(length = 10, paddingChar = ' ') + public static class DataModel { + @DataField(pos = 1, length = 10, trim = true) + @BindyConverter(CustomConverter.class) + public String field1; + } + + public static class CustomConverter implements Format<String> { + @Override + public String format(String object) throws Exception { + return (new StringBuilder(object)).reverse().toString(); + } + + @Override + public String parse(String string) throws Exception { + return (new StringBuilder(string)).reverse().toString(); + } + } +}