Repository: camel Updated Branches: refs/heads/master 9707a9e90 -> 55d1bdb39
CAMEL-11479: Add support for unmarshal single object mode in camel-beanio. Thanks to Manikanta for the test case. Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/55d1bdb3 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/55d1bdb3 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/55d1bdb3 Branch: refs/heads/master Commit: 55d1bdb39fb899503bb28a8ca3103d7eed5a564d Parents: 9707a9e Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Sep 20 09:41:12 2017 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Sep 20 09:41:12 2017 +0200 ---------------------------------------------------------------------- .../model/dataformat/BeanioDataFormat.java | 17 ++++++ .../src/main/docs/beanio-dataformat.adoc | 3 +- .../dataformat/beanio/BeanIOConfiguration.java | 9 +++ .../dataformat/beanio/BeanIODataFormat.java | 28 ++++++++- .../beanio/BeanIOUnmarshalSingleObjectTest.java | 64 ++++++++++++++++++++ .../dataformat/beanio/single-object-mapping.xml | 29 +++++++++ .../BeanIODataFormatConfiguration.java | 15 +++++ 7 files changed, 163 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/camel-core/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java b/camel-core/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java index b759bfb..16d7720 100644 --- a/camel-core/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java +++ b/camel-core/src/main/java/org/apache/camel/model/dataformat/BeanioDataFormat.java @@ -50,6 +50,8 @@ public class BeanioDataFormat extends DataFormatDefinition { private String encoding; @XmlAttribute private String beanReaderErrorHandlerType; + @XmlAttribute + private Boolean unmarshalSingleObject; public BeanioDataFormat() { super("beanio"); @@ -74,6 +76,9 @@ public class BeanioDataFormat extends DataFormatDefinition { if (beanReaderErrorHandlerType != null) { setProperty(camelContext, dataFormat, "beanReaderErrorHandlerType", beanReaderErrorHandlerType); } + if (unmarshalSingleObject != null) { + setProperty(camelContext, dataFormat, "unmarshalSingleObject", unmarshalSingleObject); + } } public String getMapping() { @@ -158,4 +163,16 @@ public class BeanioDataFormat extends DataFormatDefinition { public void setBeanReaderErrorHandlerType(String beanReaderErrorHandlerType) { this.beanReaderErrorHandlerType = beanReaderErrorHandlerType; } + + public Boolean getUnmarshalSingleObject() { + return unmarshalSingleObject; + } + + /** + * This options controls whether to unmarshal as a list of objects or as a single object only. The former is the default mode, and the latter + * is only intended in special use-cases where beanio maps the Camel message to a single POJO bean. + */ + public void setUnmarshalSingleObject(Boolean unmarshalSingleObject) { + this.unmarshalSingleObject = unmarshalSingleObject; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/components/camel-beanio/src/main/docs/beanio-dataformat.adoc ---------------------------------------------------------------------- diff --git a/components/camel-beanio/src/main/docs/beanio-dataformat.adoc b/components/camel-beanio/src/main/docs/beanio-dataformat.adoc index 23320ad..675f75a 100644 --- a/components/camel-beanio/src/main/docs/beanio-dataformat.adoc +++ b/components/camel-beanio/src/main/docs/beanio-dataformat.adoc @@ -14,7 +14,7 @@ XML] file where you define the mapping from the flat format to Objects ### Options // dataformat options: START -The BeanIO dataformat supports 8 options which are listed below. +The BeanIO dataformat supports 9 options which are listed below. @@ -28,6 +28,7 @@ The BeanIO dataformat supports 8 options which are listed below. | ignoreInvalidRecords | false | Boolean | Whether to ignore invalid records. | encoding | | String | The charset to use. Is by default the JVM platform default charset. | beanReaderErrorHandlerType | | String | To use a custom org.apache.camel.dataformat.beanio.BeanIOErrorHandler as error handler while parsing. Configure the fully qualified class name of the error handler. Notice the options ignoreUnidentifiedRecords ignoreUnexpectedRecords and ignoreInvalidRecords may not be in use when you use a custom error handler. +| unmarshalSingleObject | false | Boolean | This options controls whether to unmarshal as a list of objects or as a single object only. The former is the default mode and the latter is only intended in special use-cases where beanio maps the Camel message to a single POJO bean. | contentTypeHeader | false | Boolean | Whether the data format should set the Content-Type header with the type from the data format if the data format is capable of doing so. For example application/xml for data formats marshalling to XML or application/json for data formats marshalling to JSon etc. |=== // dataformat options: END http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIOConfiguration.java ---------------------------------------------------------------------- diff --git a/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIOConfiguration.java b/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIOConfiguration.java index fef395e..fc4d321 100644 --- a/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIOConfiguration.java +++ b/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIOConfiguration.java @@ -35,6 +35,7 @@ public class BeanIOConfiguration { private Properties properties; private BeanReaderErrorHandler beanReaderErrorHandler; private String beanReaderErrorHandlerType; + private boolean unmarshalSingleObject; public String getMapping() { return mapping; @@ -111,4 +112,12 @@ public class BeanIOConfiguration { public void setBeanReaderErrorHandlerType(Class<?> beanReaderErrorHandlerType) { this.beanReaderErrorHandlerType = beanReaderErrorHandlerType.getName(); } + + public boolean isUnmarshalSingleObject() { + return unmarshalSingleObject; + } + + public void setUnmarshalSingleObject(boolean unmarshalSingleObject) { + this.unmarshalSingleObject = unmarshalSingleObject; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIODataFormat.java ---------------------------------------------------------------------- diff --git a/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIODataFormat.java b/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIODataFormat.java index c01350b..1ef854d 100644 --- a/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIODataFormat.java +++ b/components/camel-beanio/src/main/java/org/apache/camel/dataformat/beanio/BeanIODataFormat.java @@ -31,6 +31,7 @@ import java.util.Properties; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; import org.apache.camel.Exchange; +import org.apache.camel.NoTypeConversionAvailableException; import org.apache.camel.spi.DataFormat; import org.apache.camel.spi.DataFormatName; import org.apache.camel.support.ServiceSupport; @@ -41,6 +42,7 @@ import org.beanio.BeanReader; import org.beanio.BeanReaderErrorHandler; import org.beanio.BeanWriter; import org.beanio.StreamFactory; +import org.beanio.Unmarshaller; import static org.apache.camel.dataformat.beanio.BeanIOHelper.getOrCreateBeanReaderErrorHandler; @@ -111,7 +113,11 @@ public class BeanIODataFormat extends ServiceSupport implements DataFormat, Data } public Object unmarshal(Exchange exchange, InputStream stream) throws Exception { - return readModels(exchange, stream); + if (isUnmarshalSingleObject()) { + return readSingleModel(exchange, stream); + } else { + return readModels(exchange, stream); + } } @SuppressWarnings("unchecked") @@ -163,6 +169,17 @@ public class BeanIODataFormat extends ServiceSupport implements DataFormat, Data return results; } + private Object readSingleModel(Exchange exchange, InputStream stream) throws NoTypeConversionAvailableException { + BufferedReader streamReader = IOHelper.buffered(new InputStreamReader(stream, getEncoding())); + try { + String data = exchange.getContext().getTypeConverter().mandatoryConvertTo(String.class, exchange, streamReader); + Unmarshaller unmarshaller = factory.createUnmarshaller(getStreamName()); + return unmarshaller.unmarshal(data); + } finally { + IOHelper.close(stream); + } + } + public String getMapping() { return configuration.getMapping(); } @@ -238,4 +255,13 @@ public class BeanIODataFormat extends ServiceSupport implements DataFormat, Data public void setBeanReaderErrorHandlerType(Class<?> beanReaderErrorHandlerType) { configuration.setBeanReaderErrorHandlerType(beanReaderErrorHandlerType); } + + public boolean isUnmarshalSingleObject() { + return configuration.isUnmarshalSingleObject(); + } + + public void setUnmarshalSingleObject(boolean unmarshalSingleObject) { + configuration.setUnmarshalSingleObject(unmarshalSingleObject); + } + } http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/components/camel-beanio/src/test/java/org/apache/camel/dataformat/beanio/BeanIOUnmarshalSingleObjectTest.java ---------------------------------------------------------------------- diff --git a/components/camel-beanio/src/test/java/org/apache/camel/dataformat/beanio/BeanIOUnmarshalSingleObjectTest.java b/components/camel-beanio/src/test/java/org/apache/camel/dataformat/beanio/BeanIOUnmarshalSingleObjectTest.java new file mode 100644 index 0000000..f929182 --- /dev/null +++ b/components/camel-beanio/src/test/java/org/apache/camel/dataformat/beanio/BeanIOUnmarshalSingleObjectTest.java @@ -0,0 +1,64 @@ +/** + * 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.beanio; + +import java.util.Map; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.test.junit4.CamelTestSupport; +import org.junit.Test; + +public class BeanIOUnmarshalSingleObjectTest extends CamelTestSupport { + + private static final String NEW_LINE = "\n"; + private static final String INPUT = "1234:Content starts from here" + NEW_LINE + "then continues" + NEW_LINE + "and ends here."; + + @Test + public void testMultiLineContentUnmarshal() throws Exception { + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + + template.sendBody("direct:unmarshal", INPUT); + + mock.assertIsSatisfied(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + BeanIODataFormat format = new BeanIODataFormat("org/apache/camel/dataformat/beanio/single-object-mapping.xml", "keyValueStream"); + // turn on single mode + format.setUnmarshalSingleObject(true); + + from("direct:unmarshal").unmarshal(format).process(new Processor() { + public void process(Exchange exchange) throws Exception { + Map body = (Map) exchange.getIn().getBody(); + assertEquals(":", body.get("separator")); + assertEquals("1234", body.get("key")); + assertEquals(INPUT.substring(5), body.get("value")); + } + }).marshal(format).to("mock:result"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/components/camel-beanio/src/test/resources/org/apache/camel/dataformat/beanio/single-object-mapping.xml ---------------------------------------------------------------------- diff --git a/components/camel-beanio/src/test/resources/org/apache/camel/dataformat/beanio/single-object-mapping.xml b/components/camel-beanio/src/test/resources/org/apache/camel/dataformat/beanio/single-object-mapping.xml new file mode 100644 index 0000000..8434cb8 --- /dev/null +++ b/components/camel-beanio/src/test/resources/org/apache/camel/dataformat/beanio/single-object-mapping.xml @@ -0,0 +1,29 @@ +<?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. + +--> +<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd"> + <stream name="keyValueStream" format="fixedlength"> + <record name="entry" class="map" minOccurs="1"> + <field name="key" length="4" required="true" justify="left" /> + <field name="separator" length="1" required="true" justify="left" /> + <field name="value" required="true" length="unbounded" justify="left" /> + </record> + </stream> +</beanio> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/camel/blob/55d1bdb3/platforms/spring-boot/components-starter/camel-beanio-starter/src/main/java/org/apache/camel/dataformat/beanio/springboot/BeanIODataFormatConfiguration.java ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-beanio-starter/src/main/java/org/apache/camel/dataformat/beanio/springboot/BeanIODataFormatConfiguration.java b/platforms/spring-boot/components-starter/camel-beanio-starter/src/main/java/org/apache/camel/dataformat/beanio/springboot/BeanIODataFormatConfiguration.java index 1b68ba5..112f44c 100644 --- a/platforms/spring-boot/components-starter/camel-beanio-starter/src/main/java/org/apache/camel/dataformat/beanio/springboot/BeanIODataFormatConfiguration.java +++ b/platforms/spring-boot/components-starter/camel-beanio-starter/src/main/java/org/apache/camel/dataformat/beanio/springboot/BeanIODataFormatConfiguration.java @@ -66,6 +66,13 @@ public class BeanIODataFormatConfiguration */ private String beanReaderErrorHandlerType; /** + * This options controls whether to unmarshal as a list of objects or as a + * single object only. The former is the default mode and the latter is only + * intended in special use-cases where beanio maps the Camel message to a + * single POJO bean. + */ + private Boolean unmarshalSingleObject = false; + /** * Whether the data format should set the Content-Type header with the type * from the data format if the data format is capable of doing so. For * example application/xml for data formats marshalling to XML or @@ -129,6 +136,14 @@ public class BeanIODataFormatConfiguration this.beanReaderErrorHandlerType = beanReaderErrorHandlerType; } + public Boolean getUnmarshalSingleObject() { + return unmarshalSingleObject; + } + + public void setUnmarshalSingleObject(Boolean unmarshalSingleObject) { + this.unmarshalSingleObject = unmarshalSingleObject; + } + public Boolean getContentTypeHeader() { return contentTypeHeader; }