You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ff...@apache.org on 2022/03/17 20:15:48 UTC
[camel-spring-boot] branch main updated: [CAMEL-17807]add tests in camel-jaxb-starter (#473)
This is an automated email from the ASF dual-hosted git repository.
ffang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/main by this push:
new 7860fca [CAMEL-17807]add tests in camel-jaxb-starter (#473)
7860fca is described below
commit 7860fca6ce1213ffd7f01d027e5ea65d3c46346f
Author: Freeman(Yue) Fang <fr...@gmail.com>
AuthorDate: Thu Mar 17 16:14:23 2022 -0400
[CAMEL-17807]add tests in camel-jaxb-starter (#473)
---
.../camel/converter/jaxb/address/Address.java | 103 +++++++
.../converter/jaxb/address/ObjectFactory.java | 49 ++++
.../camel/converter/jaxb/address/package-info.java | 19 ++
.../camel/converter/jaxb/message/Message.java | 82 ++++++
.../converter/jaxb/message/ObjectFactory.java | 57 ++++
.../camel/converter/jaxb/message/package-info.java | 18 ++
.../camel/converter/jaxb/person/ObjectFactory.java | 49 ++++
.../apache/camel/converter/jaxb/person/Person.java | 164 +++++++++++
.../camel/converter/jaxb/person/package-info.java | 19 ++
.../converter/jaxb/springboot/CamelJaxbTest.java | 299 +++++++++++++++++++++
...ncurrentJaxbDataFormatSchemaValidationTest.java | 167 ++++++++++++
.../jaxb/springboot/DataFormatComponentTest.java | 63 +++++
.../converter/jaxb/springboot/DataFormatTest.java | 136 ++++++++++
.../springboot/DirectBeanToBeanPersonTypeTest.java | 89 ++++++
.../ExplicitEncodingAndXMLCharFilteringTest.java | 118 ++++++++
.../jaxb/springboot/ExplicitFileEncodingTest.java | 109 ++++++++
...lbackTypeConverterShouldThrowExceptionTest.java | 171 ++++++++++++
.../converter/jaxb/springboot/FromFileBase.java | 73 +++++
.../springboot/JaxbConcurrentDataFormatTest.java | 124 +++++++++
.../JaxbDataFormatMultipleNamespacesTest.java | 150 +++++++++++
.../JaxbDataFormatPartClassHeaderTest.java | 125 +++++++++
.../springboot/JaxbDataFormatPartClassTest.java | 122 +++++++++
.../JaxbDataFormatSchemaValidationTest.java | 189 +++++++++++++
...ormatSchemaValidationWithObjectFactoryTest.java | 153 +++++++++++
.../jaxb/springboot/JaxbErrorLogTest.java | 148 ++++++++++
.../jaxb/springboot/RouteWithErrorHandlerTest.java | 154 +++++++++++
.../TimerBeanToBeanNotificationTypeTest.java | 89 ++++++
.../converter/jaxb/springboot/UnmarshalTest.java | 95 +++++++
.../java/org/apache/camel/example/Address.java | 68 +++++
.../test/java/org/apache/camel/example/Bar.java | 52 ++++
.../test/java/org/apache/camel/example/Foo.java | 43 +++
.../camel/example/InvalidOrderException.java | 25 ++
.../test/java/org/apache/camel/example/Order.java | 49 ++++
.../java/org/apache/camel/example/Partial.java | 81 ++++++
.../org/apache/camel/example/PurchaseOrder.java | 79 ++++++
.../test/java/org/apache/camel/example/Zot.java | 35 +++
.../org/apache/camel/example/package-info.java | 25 ++
.../org/apache/camel/foo/bar/ObjectFactory.java | 63 +++++
.../java/org/apache/camel/foo/bar/PersonType.java | 113 ++++++++
.../camel/jaxb/CamelJaxbFallbackConverterTest.java | 126 +++++++++
.../camel/jaxb/CamelJaxbNoNamespaceSchemaTest.java | 87 ++++++
...backTypeConverterObjectFactoryDisabledTest.java | 91 +++++++
...lbackTypeConverterObjectFactoryEnabledTest.java | 112 ++++++++
...lbackTypeConverterShouldThrowExceptionTest.java | 154 +++++++++++
.../apache/camel/jaxb/JaxbDataFormatIssueTest.java | 91 +++++++
.../jaxb/JaxbDataFormatMustBeJAXBElementTest.java | 122 +++++++++
.../jaxb/JaxbMarshalNamespacePrefixMapperTest.java | 116 ++++++++
.../apache/camel/jaxb/MyNotificationService.java | 39 +++
.../org/apache/camel/jaxb/MyPersonService.java | 41 +++
.../org/apache/camel/jaxb/NotificationType.java | 39 +++
.../SplitterAndExceptionRouteTwistIssueTest.java | 223 +++++++++++++++
.../org/apache/camel/jaxb/TestXmlStreamWriter.java | 190 +++++++++++++
.../src/test/resources/address.xsd | 32 +++
.../src/test/resources/message.xml | 22 ++
.../src/test/resources/message.xsd | 32 +++
.../resources/org/apache/camel/example/jaxb.index | 23 ++
.../src/test/resources/person.xsd | 38 +++
57 files changed, 5345 insertions(+)
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/Address.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/Address.java
new file mode 100644
index 0000000..e20247d
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/Address.java
@@ -0,0 +1,103 @@
+/*
+ * 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.converter.jaxb.address;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * <p>
+ * Java class for address complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="address">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="addressLine1" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="addressLine2" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "address", propOrder = { "addressLine1", "addressLine2" })
+public class Address {
+
+ @XmlElement(required = true)
+ protected String addressLine1;
+ protected String addressLine2;
+
+ /**
+ * Gets the value of the addressLine1 property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getAddressLine1() {
+ return addressLine1;
+ }
+
+ /**
+ * Sets the value of the addressLine1 property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setAddressLine1(String value) {
+ this.addressLine1 = value;
+ }
+
+ /**
+ * Gets the value of the addressLine2 property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getAddressLine2() {
+ return addressLine2;
+ }
+
+ /**
+ * Sets the value of the addressLine2 property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setAddressLine2(String value) {
+ this.addressLine2 = value;
+ }
+
+ public Address withAddressLine1(String value) {
+ setAddressLine1(value);
+ return this;
+ }
+
+ public Address withAddressLine2(String value) {
+ setAddressLine2(value);
+ return this;
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/ObjectFactory.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/ObjectFactory.java
new file mode 100644
index 0000000..a242d01
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/ObjectFactory.java
@@ -0,0 +1,49 @@
+/*
+ * 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.converter.jaxb.address;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+/**
+ * This object contains factory methods for each Java content interface and Java element interface generated in the
+ * org.apache.camel.converter.jaxb.address package.
+ * <p>
+ * An ObjectFactory allows you to programatically construct new instances of the Java representation for XML content.
+ * The Java representation of XML content can consist of schema derived interfaces and classes representing the binding
+ * of schema type definitions, element declarations and model groups. Factory methods for each of these are provided in
+ * this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package:
+ * org.apache.camel.converter.jaxb.address
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Address }
+ *
+ */
+ public Address createAddress() {
+ return new Address();
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/package-info.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/package-info.java
new file mode 100644
index 0000000..0e38a34
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/address/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "address.jaxb.converter.camel.apache.org",
+ elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.camel.converter.jaxb.address;
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/Message.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
new file mode 100644
index 0000000..d128104
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/Message.java
@@ -0,0 +1,82 @@
+/*
+ * 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.converter.jaxb.message;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * <p>
+ * Java class for anonymous complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="text" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = { "text" })
+public class Message {
+
+ @XmlElement(required = true)
+ private String text;
+
+ public Message() {
+ }
+
+ public Message(String text) {
+ this.text = text;
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Message)) {
+ return false;
+ }
+ Message message = (Message) o;
+ return getText() != null ? getText().equals(message.getText()) : message.getText() == null;
+ }
+
+ @Override
+ public int hashCode() {
+ return getText() != null ? getText().hashCode() : 0;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
new file mode 100644
index 0000000..c1ac836
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/ObjectFactory.java
@@ -0,0 +1,57 @@
+/*
+ * 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.converter.jaxb.message;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+/**
+ * This object contains factory methods for each Java content interface and Java element interface generated in the
+ * org.apache.camel.converter.jaxb.message package.
+ * <p>
+ * An ObjectFactory allows you to programatically construct new instances of the Java representation for XML content.
+ * The Java representation of XML content can consist of schema derived interfaces and classes representing the binding
+ * of schema type definitions, element declarations and model groups. Factory methods for each of these are provided in
+ * this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private static final QName MESSAGE_QNAME = new QName("message.jaxb.converter.camel.apache.org", "message");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package:
+ * org.apache.camel.converter.jaxb.message
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Message }
+ */
+ public Message createMessage() {
+ return new Message();
+ }
+
+ @XmlElementDecl(namespace = "message.jaxb.converter.camel.apache.org", name = "message")
+ public JAXBElement<Message> createMessage(Message value) {
+ return new JAXBElement<>(MESSAGE_QNAME, Message.class, null, value);
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
new file mode 100644
index 0000000..bd5591d
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/message/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "message.jaxb.converter.camel.apache.org")
+package org.apache.camel.converter.jaxb.message;
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/ObjectFactory.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/ObjectFactory.java
new file mode 100644
index 0000000..6fdd150
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/ObjectFactory.java
@@ -0,0 +1,49 @@
+/*
+ * 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.converter.jaxb.person;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+/**
+ * This object contains factory methods for each Java content interface and Java element interface generated in the
+ * org.apache.camel.converter.jaxb.person package.
+ * <p>
+ * An ObjectFactory allows you to programatically construct new instances of the Java representation for XML content.
+ * The Java representation of XML content can consist of schema derived interfaces and classes representing the binding
+ * of schema type definitions, element declarations and model groups. Factory methods for each of these are provided in
+ * this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package:
+ * org.apache.camel.converter.jaxb.person
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link Person }
+ *
+ */
+ public Person createPerson() {
+ return new Person();
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/Person.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/Person.java
new file mode 100644
index 0000000..ebc4556
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/Person.java
@@ -0,0 +1,164 @@
+/*
+ * 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.converter.jaxb.person;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.camel.converter.jaxb.address.Address;
+
+/**
+ * <p>
+ * Java class for anonymous complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="firstName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="age" type="{http://www.w3.org/2001/XMLSchema}int"/>
+ * <element name="address" type="{address.jaxb.converter.camel.apache.org}address"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = { "firstName", "lastName", "age", "address" })
+@XmlRootElement(name = "person")
+public class Person {
+
+ @XmlElement(required = true)
+ protected String firstName;
+ @XmlElement(required = true)
+ protected String lastName;
+ @XmlElement(required = true, type = Integer.class, nillable = true)
+ protected Integer age;
+ @XmlElement(required = true)
+ protected Address address;
+
+ /**
+ * Gets the value of the firstName property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ /**
+ * Sets the value of the firstName property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setFirstName(String value) {
+ this.firstName = value;
+ }
+
+ /**
+ * Gets the value of the lastName property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getLastName() {
+ return lastName;
+ }
+
+ /**
+ * Sets the value of the lastName property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setLastName(String value) {
+ this.lastName = value;
+ }
+
+ /**
+ * Gets the value of the age property.
+ *
+ * @return possible object is {@link Integer }
+ *
+ */
+ public Integer getAge() {
+ return age;
+ }
+
+ /**
+ * Sets the value of the age property.
+ *
+ * @param value allowed object is {@link Integer }
+ *
+ */
+ public void setAge(Integer value) {
+ this.age = value;
+ }
+
+ /**
+ * Gets the value of the address property.
+ *
+ * @return possible object is {@link Address }
+ *
+ */
+ public Address getAddress() {
+ return address;
+ }
+
+ /**
+ * Sets the value of the address property.
+ *
+ * @param value allowed object is {@link Address }
+ *
+ */
+ public void setAddress(Address value) {
+ this.address = value;
+ }
+
+ public Person withFirstName(String value) {
+ setFirstName(value);
+ return this;
+ }
+
+ public Person withLastName(String value) {
+ setLastName(value);
+ return this;
+ }
+
+ public Person withAge(Integer value) {
+ setAge(value);
+ return this;
+ }
+
+ public Person withAddress(Address value) {
+ setAddress(value);
+ return this;
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/package-info.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/package-info.java
new file mode 100644
index 0000000..512a578
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/person/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+@javax.xml.bind.annotation.XmlSchema(namespace = "person.jaxb.converter.camel.apache.org",
+ elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
+package org.apache.camel.converter.jaxb.person;
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/CamelJaxbTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/CamelJaxbTest.java
new file mode 100644
index 0000000..81f1df4
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/CamelJaxbTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.bind.JAXBElement;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.foo.bar.PersonType;
+import org.apache.camel.jaxb.TestXmlStreamWriter;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ CamelJaxbTest.class,
+ CamelJaxbTest.TestConfiguration.class
+ }
+)
+public class CamelJaxbTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint resultEndpoint;
+
+
+
+ @Test
+ public void testUnmarshalBadCharsWithFiltering() throws Exception {
+ resultEndpoint.reset();
+ String xml = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>";
+
+ PersonType expected = new PersonType();
+ expected.setFirstName("FOO");
+ expected.setLastName("BAR ");
+
+ resultEndpoint.expectedBodiesReceived(expected);
+
+ template.sendBody("direct:unmarshalFilteringEnabled", xml);
+ resultEndpoint.assertIsSatisfied();
+ }
+
+ @Test
+ public void testUnmarshalBadCharsNoFiltering() throws Exception {
+ String xml = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>";
+ assertThrows(CamelExecutionException.class, () -> template.sendBody("direct:getJAXBElementValue", xml));
+ }
+
+ @Test
+ public void testFilterNonXmlChars() throws Exception {
+ resultEndpoint.reset();
+ String xmlUTF = "<Person><firstName>FOO</firstName><lastName>BAR \u20AC </lastName></Person>";
+ String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + xmlUTF;
+ PersonType expected = new PersonType();
+ expected.setFirstName("FOO");
+ expected.setLastName("BAR \u20AC ");
+ resultEndpoint.expectedBodiesReceived(expected);
+ template.sendBody("direct:unmarshalFilteringEnabled", xml);
+ resultEndpoint.assertIsSatisfied();
+
+ }
+
+ @Test
+ public void testMarshalBadCharsWithFiltering() throws Exception {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo\u0004");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ template.sendBody("direct:marshalFilteringEnabled", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertFalse(body.contains("\u0004"), "Non-xml character wasn't replaced");
+ }
+
+ @Test
+ public void testMarshalBadCharsNoFiltering() throws Exception {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo\u0004");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ resultEndpoint.expectedHeaderReceived(Exchange.CONTENT_TYPE, "application/xml");
+ template.sendBody("direct:marshal", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertTrue(body.contains("\u0004"), "Non-xml character unexpectedly did not get into marshalled contents");
+ }
+
+ @Test
+ public void testMarshalWithSchemaLocation() throws Exception {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ resultEndpoint.expectedHeaderReceived(Exchange.CONTENT_TYPE, "application/xml");
+ template.sendBody("direct:marshal", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertTrue(body.contains("schemaLocation=\"person.xsd\""), "We should get the schemaLocation here");
+ }
+
+ @Test
+ public void testMarshalWithoutContentType() throws Exception {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ resultEndpoint.expectedHeaderReceived(Exchange.CONTENT_TYPE, null);
+ template.sendBody("direct:marshalWithoutContentType", person);
+ resultEndpoint.assertIsSatisfied();
+ }
+
+ @Test
+ public void testCustomXmlStreamWriter() throws InterruptedException {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ template.sendBody("direct:marshalCustomWriter", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertTrue(body.contains("-Foo"), "Body did not get processed correctly by custom filter");
+ }
+
+ @Test
+ public void testCustomXmlStreamWriterAndFiltering() throws InterruptedException {
+ resultEndpoint.reset();
+ PersonType person = new PersonType();
+ person.setFirstName("foo\u0004");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ template.sendBody("direct:marshalCustomWriterAndFiltering", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertFalse(body.contains("\u0004"), "Non-xml character unexpectedly did not get into marshalled contents");
+ assertTrue(body.contains("-Foo"), "Body did not get processed correctly by custom filter");
+ }
+
+ @Test
+ public void testUnmarshal() throws Exception {
+ resultEndpoint.reset();
+ final String xml = "<Person><firstName>FOO</firstName><lastName>BAR</lastName></Person>";
+ PersonType expected = new PersonType();
+ expected.setFirstName("FOO");
+ expected.setLastName("BAR");
+
+ resultEndpoint.expectedBodiesReceived(expected);
+ resultEndpoint.expectedHeaderReceived("foo", "bar");
+ template.sendBodyAndHeader("direct:getJAXBElementValue", xml, "foo", "bar");
+
+ resultEndpoint.assertIsSatisfied();
+ resultEndpoint.reset();
+ resultEndpoint.expectedMessageCount(1);
+ template.sendBody("direct:getJAXBElement", xml);
+ resultEndpoint.assertIsSatisfied();
+ assertTrue(resultEndpoint.getExchanges().get(0).getIn().getBody() instanceof JAXBElement,
+ "We should get the JAXBElement here");
+
+ resultEndpoint.reset();
+ resultEndpoint.expectedMessageCount(1);
+ resultEndpoint.expectedBodiesReceived(expected);
+ template.sendBody("direct:unmarshall", xml);
+ resultEndpoint.assertIsSatisfied();
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat dataFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+ dataFormat.setSchemaLocation("person.xsd");
+ dataFormat.setIgnoreJAXBElement(false);
+
+ JaxbDataFormat dataFormatWithoutContentType = new JaxbDataFormat("org.apache.camel.foo.bar");
+ dataFormat.setIgnoreJAXBElement(false);
+ dataFormatWithoutContentType.setContentTypeHeader(false);
+
+ JaxbDataFormat filterEnabledFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+ filterEnabledFormat.setFilterNonXmlChars(true);
+
+ JaxbDataFormat customWriterFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+ customWriterFormat.setXmlStreamWriterWrapper(new TestXmlStreamWriter());
+
+ JaxbDataFormat customWriterAndFilterFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+ customWriterAndFilterFormat.setFilterNonXmlChars(true);
+ customWriterAndFilterFormat.setXmlStreamWriterWrapper(new TestXmlStreamWriter());
+
+ from("direct:getJAXBElementValue")
+ .unmarshal(new JaxbDataFormat("org.apache.camel.foo.bar"))
+ .to("mock:result");
+
+ from("direct:getJAXBElement")
+ .unmarshal(dataFormat)
+ .to("mock:result");
+
+ from("direct:unmarshalFilteringEnabled")
+ .unmarshal(filterEnabledFormat)
+ .to("mock:result");
+
+ from("direct:marshal")
+ .marshal(dataFormat)
+ .to("mock:result");
+
+ from("direct:marshalWithoutContentType")
+ .marshal(dataFormatWithoutContentType)
+ .to("mock:result");
+
+ from("direct:marshalFilteringEnabled")
+ .marshal(filterEnabledFormat)
+ .to("mock:result");
+
+ from("direct:marshalCustomWriter")
+ .marshal(customWriterFormat)
+ .to("mock:result");
+ from("direct:marshalCustomWriterAndFiltering")
+ .marshal(customWriterAndFilterFormat)
+ .to("mock:result");
+
+ from("direct:unmarshall")
+ .unmarshal()
+ .jaxb(PersonType.class.getPackage().getName())
+ .to("mock:result");
+
+ }
+ };
+
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ConcurrentJaxbDataFormatSchemaValidationTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ConcurrentJaxbDataFormatSchemaValidationTest.java
new file mode 100644
index 0000000..31e97e1
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ConcurrentJaxbDataFormatSchemaValidationTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import java.util.concurrent.TimeUnit;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.converter.jaxb.address.Address;
+import org.apache.camel.converter.jaxb.person.Person;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ ConcurrentJaxbDataFormatSchemaValidationTest.class,
+ ConcurrentJaxbDataFormatSchemaValidationTest.TestConfiguration.class
+ }
+)
+public class ConcurrentJaxbDataFormatSchemaValidationTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ConcurrentJaxbDataFormatSchemaValidationTest.class);
+
+ private int testCount = 1000;
+ private int concurrencyLevel = 10;
+
+ @Autowired
+ ProducerTemplate template;
+
+ @Autowired
+ CamelContext context;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+
+ @Test
+ public void concurrentMarshallSuccess() throws Exception {
+ mockMarshall.expectedMessageCount(testCount);
+
+ Address address = new Address();
+ address.setAddressLine1("Hauptstr. 1; 01129 Entenhausen");
+ Person person = new Person();
+ person.setFirstName("Christian");
+ person.setLastName("Mueller");
+ person.setAge(Integer.valueOf(36));
+ person.setAddress(address);
+
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < testCount; i++) {
+ template.sendBody("seda:marshall", person);
+ }
+
+ mockMarshall.assertIsSatisfied();
+ LOG.info("Validation of {} messages took {} ms", testCount, System.currentTimeMillis() - start);
+
+ String payload = mockMarshall.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(payload);
+
+ assertTrue(payload.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"));
+ assertTrue(payload.contains(
+ "<person xmlns=\"person.jaxb.converter.camel.apache.org\" xmlns:ns2=\"address.jaxb.converter.camel.apache.org\">"));
+ assertTrue(payload.contains("<firstName>Christian</firstName>"));
+ assertTrue(payload.contains("<lastName>Mueller</lastName>"));
+ assertTrue(payload.contains("<age>36</age>"));
+ assertTrue(payload.contains("<address>"));
+ assertTrue(payload.contains("<ns2:addressLine1>Hauptstr. 1; 01129 Entenhausen</ns2:addressLine1>"));
+ assertTrue(payload.contains("</address>"));
+ assertTrue(payload.contains("</person>"));
+ }
+
+ @Test
+ public void concurrentUnmarshall() throws Exception {
+ mockUnmarshall.expectedMessageCount(testCount);
+
+ String xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
+ .append("<person xmlns=\"person.jaxb.converter.camel.apache.org\" xmlns:ns2=\"address.jaxb.converter.camel.apache.org\">")
+ .append("<firstName>Christian</firstName>")
+ .append("<lastName>Mueller</lastName>")
+ .append("<age>36</age>")
+ .append("<address>")
+ .append("<ns2:addressLine1>Hauptstr. 1; 01129 Entenhausen</ns2:addressLine1>")
+ .append("</address>")
+ .append("</person>")
+ .toString();
+
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < testCount; i++) {
+ template.sendBody("seda:unmarshall", xml);
+ }
+
+ MockEndpoint.assertIsSatisfied(context, 20, TimeUnit.SECONDS);
+ LOG.info("Validation of {} messages took {} ms", testCount, System.currentTimeMillis() - start);
+
+ Person person = mockUnmarshall.getExchanges().get(0).getIn().getBody(Person.class);
+
+ assertEquals("Christian", person.getFirstName());
+ assertEquals("Mueller", person.getLastName());
+ assertEquals(Integer.valueOf(36), person.getAge());
+ }
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
+ jaxbDataFormat.setContextPath(Person.class.getPackage().getName());
+ jaxbDataFormat.setSchema("classpath:person.xsd,classpath:address.xsd");
+
+ from("seda:marshall?concurrentConsumers=" + concurrencyLevel)
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+
+ from("seda:unmarshall?concurrentConsumers=" + concurrencyLevel)
+ .unmarshal(jaxbDataFormat)
+ .to("mock:unmarshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatComponentTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatComponentTest.java
new file mode 100644
index 0000000..64e00f4
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatComponentTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+
+
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ DataFormatComponentTest.class,
+ DataFormatComponentTest.TestConfiguration.class
+ }
+)
+public class DataFormatComponentTest extends DataFormatTest {
+
+
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:start").to("dataformat:jaxb:marshal?contextPath=org.apache.camel.example").to("direct:marshalled");
+
+ from("direct:marshalled").to("dataformat:jaxb:unmarshal?contextPath=org.apache.camel.example")
+ .to("mock:result");
+
+ from("direct:prettyPrint").to("dataformat:jaxb:marshal?contextPath=org.apache.camel.foo.bar&prettyPrint=true")
+ .to("mock:result");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatTest.java
new file mode 100644
index 0000000..a0babc3
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DataFormatTest.java
@@ -0,0 +1,136 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.foo.bar.PersonType;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ DataFormatTest.class,
+ DataFormatTest.TestConfiguration.class
+ }
+)
+public class DataFormatTest {
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint resultEndpoint;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+
+
+
+ @Test
+ public void testMarshalThenUnmarshalBean() throws Exception {
+ resultEndpoint.reset();
+ PurchaseOrder bean = new PurchaseOrder();
+ bean.setName("Beer");
+ bean.setAmount(23);
+ bean.setPrice(2.5);
+
+ resultEndpoint.expectedBodiesReceived(bean);
+
+ template.sendBody("direct:start", bean);
+
+ resultEndpoint.assertIsSatisfied();
+ }
+
+ @Test
+ public void testMarshalPrettyPrint() throws Exception {
+ resultEndpoint.reset();
+
+ PersonType person = new PersonType();
+ person.setFirstName("Willem");
+ person.setLastName("Jiang");
+ resultEndpoint.expectedMessageCount(1);
+
+ template.sendBody("direct:prettyPrint", person);
+
+ resultEndpoint.assertIsSatisfied();
+
+ Exchange exchange = resultEndpoint.getExchanges().get(0);
+
+ String result = exchange.getIn().getBody(String.class);
+ assertNotNull("The result should not be null", result);
+ int indexPerson = result.indexOf("<Person>");
+ int indexFirstName = result.indexOf("<firstName>");
+
+ assertTrue(indexPerson > 0, "we should find the <Person>");
+ assertTrue(indexFirstName > 0, "we should find the <firstName>");
+ assertTrue(indexFirstName - indexPerson > 8, "There should some sapce between <Person> and <firstName>");
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+
+ JaxbDataFormat example = new JaxbDataFormat("org.apache.camel.example");
+ JaxbDataFormat person = new JaxbDataFormat("org.apache.camel.foo.bar");
+ person.setPrettyPrint(true);
+
+ from("direct:start").marshal(example).to("direct:marshalled");
+
+ from("direct:marshalled").unmarshal().jaxb("org.apache.camel.example").to("mock:result");
+
+ from("direct:prettyPrint").marshal(person).to("mock:result");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DirectBeanToBeanPersonTypeTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DirectBeanToBeanPersonTypeTest.java
new file mode 100644
index 0000000..86946f6
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/DirectBeanToBeanPersonTypeTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.foo.bar.PersonType;
+import org.apache.camel.jaxb.MyPersonService;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ DirectBeanToBeanPersonTypeTest.class,
+ DirectBeanToBeanPersonTypeTest.TestConfiguration.class
+ }
+)
+public class DirectBeanToBeanPersonTypeTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:person")
+ private MockEndpoint mock;
+
+ @Test
+ public void testBeanToBean() throws Exception {
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(PersonType.class);
+
+ template.sendBody("direct:start", null);
+
+ mock.assertIsSatisfied();
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:start")
+ .bean(MyPersonService.class, "createPerson")
+ .bean(MyPersonService.class, "sendPerson");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitEncodingAndXMLCharFilteringTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitEncodingAndXMLCharFilteringTest.java
new file mode 100644
index 0000000..00f1c53
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitEncodingAndXMLCharFilteringTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ ExplicitEncodingAndXMLCharFilteringTest.class,
+ ExplicitEncodingAndXMLCharFilteringTest.TestConfiguration.class
+ }
+)
+public class ExplicitEncodingAndXMLCharFilteringTest extends FromFileBase {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:file")
+ private MockEndpoint result;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+
+ @Test
+ public void testIsoAndCharacterFiltering() throws Exception {
+ PurchaseOrder order = new PurchaseOrder();
+ //Data containing characters ÆØÅæøå that differ in utf-8 and iso + a spouting whale
+ String name = "\u00c6\u00d8\u00C5\u00e6\u00f8\u00e5\uD83D\uDC33\uFFFD";
+ String expected = "\u00c6\u00d8\u00C5\u00e6\u00f8\u00e5 \uFFFD"; //Spouting whale has become spaces
+ order.setName(name);
+ order.setAmount(123.45);
+ order.setPrice(2.22);
+
+ result.expectedFileExists(testFile("output.xml"));
+
+ template.sendBody("direct:start", order);
+ result.assertIsSatisfied();
+
+ JAXBContext jaxbContext = JAXBContext.newInstance("org.apache.camel.example");
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ InputStream inputStream = new FileInputStream(testFile("output.xml").toFile());
+ Reader reader = new InputStreamReader(inputStream, StandardCharsets.ISO_8859_1);
+ PurchaseOrder obj = (PurchaseOrder) unmarshaller.unmarshal(reader);
+ assertEquals(expected, obj.getName());
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxb = new JaxbDataFormat("org.apache.camel.example");
+ jaxb.setFilterNonXmlChars(true);
+ jaxb.setEncoding("iso-8859-1");
+
+ from("direct:start")
+ .marshal(jaxb)
+ .to(fileUri("?fileName=output.xml&charset=iso-8859-1"));
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitFileEncodingTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitFileEncodingTest.java
new file mode 100644
index 0000000..4fd252d
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/ExplicitFileEncodingTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ ExplicitFileEncodingTest.class,
+ ExplicitFileEncodingTest.TestConfiguration.class
+ }
+)
+public class ExplicitFileEncodingTest extends FromFileBase {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:file")
+ private MockEndpoint result;
+
+
+ @Test
+ public void testISOFileEncoding() throws Exception {
+ PurchaseOrder order = new PurchaseOrder();
+ //Data containing characters ÆØÅæøå that differ in utf-8 and iso
+ String name = "\u00c6\u00d8\u00C5\u00e6\u00f8\u00e5";
+ order.setName(name);
+ order.setAmount(123.45);
+ order.setPrice(2.22);
+
+
+ result.expectedFileExists(testFile("output.txt"));
+
+ template.sendBody("direct:start", order);
+ result.assertIsSatisfied();
+
+ JAXBContext jaxbContext = JAXBContext.newInstance("org.apache.camel.example");
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ PurchaseOrder obj = (PurchaseOrder) unmarshaller.unmarshal(testFile("output.txt").toFile());
+ assertEquals(obj.getName(), name);
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxb = new JaxbDataFormat("org.apache.camel.example");
+ jaxb.setEncoding("iso-8859-1");
+
+ from("direct:start")
+ .marshal(jaxb)
+ .to(fileUri("?fileName=output.txt&charset=iso-8859-1"));
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FallbackTypeConverterShouldThrowExceptionTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FallbackTypeConverterShouldThrowExceptionTest.java
new file mode 100644
index 0000000..ad44b81
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FallbackTypeConverterShouldThrowExceptionTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.TypeConversionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.example.Bar;
+import org.apache.camel.example.Foo;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ FallbackTypeConverterShouldThrowExceptionTest.class,
+ FallbackTypeConverterShouldThrowExceptionTest.TestConfiguration.class
+ }
+)
+public class FallbackTypeConverterShouldThrowExceptionTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+ @Autowired
+ CamelContext context;
+
+
+ @EndpointInject("mock:a")
+ private MockEndpoint mockA;
+
+ @EndpointInject("mock:b")
+ private MockEndpoint mockB;
+
+
+ private static AtomicInteger failed = new AtomicInteger();
+ private static AtomicInteger failed2 = new AtomicInteger();
+
+ @BeforeEach
+ public void setup() {
+ failed = new AtomicInteger();
+ failed2 = new AtomicInteger();
+ }
+
+ @Test
+ public void testJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object foo = new Foo();
+ mockA.expectedBodiesReceived(foo);
+ mockB.expectedBodiesReceived(foo);
+
+ template.sendBody("direct:a", foo);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(0, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ @Test
+ public void testNoneJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object camel = "Camel";
+ mockA.expectedBodiesReceived(camel);
+ mockB.expectedBodiesReceived(camel);
+
+ template.sendBody("direct:a", camel);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(1, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ @Test
+ public void testAnotherJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object bar = new Bar();
+ mockA.expectedBodiesReceived(bar);
+ mockB.expectedBodiesReceived(bar);
+
+ template.sendBody("direct:a", bar);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(1, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:a").process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ try {
+ exchange.getIn().getBody(Foo.class);
+ } catch (TypeConversionException e) {
+ failed.incrementAndGet();
+ }
+ }
+ }).to("mock:a").process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ try {
+ exchange.getIn().getBody(List.class);
+ } catch (TypeConversionException e) {
+ // there is no type converters from the POJO -> List
+ // so we should really not fail at all at this point
+ failed2.incrementAndGet();
+ }
+ }
+
+ }).to("mock:b");
+ }
+
+ };
+
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FromFileBase.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FromFileBase.java
new file mode 100644
index 0000000..5eef1ae
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/FromFileBase.java
@@ -0,0 +1,73 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+import static org.apache.camel.test.junit5.TestSupport.deleteDirectory;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class FromFileBase {
+
+ private boolean testDirectoryCleaned;
+
+ protected String fileUri() {
+ return "file:" + testDirectory();
+ }
+
+ protected String fileUri(String query) {
+ return "file:" + testDirectory() + (query.startsWith("?") ? "" : "/") + query;
+ }
+
+ protected Path testDirectory() {
+ return testDirectory(false);
+ }
+
+ protected Path testDirectory(boolean create) {
+ Class<?> testClass = getClass();
+ return testDirectory(testClass, create);
+ }
+
+
+
+ protected static Path testDirectory(Class<?> testClass, boolean create) {
+ Path dir = Paths.get("target", "data", testClass.getSimpleName());
+ if (create) {
+ try {
+ Files.createDirectories(dir);
+ } catch (IOException e) {
+ throw new IllegalStateException("Unable to create test directory: " + dir, e);
+ }
+ }
+ return dir;
+ }
+
+ protected Path testFile(String dir) {
+ return testDirectory().resolve(dir);
+ }
+
+ public void deleteTestDirectory() {
+ if (!testDirectoryCleaned) {
+ deleteDirectory(testDirectory());
+ testDirectoryCleaned = true;
+ }
+ }
+
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbConcurrentDataFormatTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbConcurrentDataFormatTest.java
new file mode 100644
index 0000000..8f19100
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbConcurrentDataFormatTest.java
@@ -0,0 +1,124 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import static org.apache.camel.test.junit5.TestSupport.body;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbConcurrentDataFormatTest.class,
+ JaxbConcurrentDataFormatTest.TestConfiguration.class
+ }
+)
+public class JaxbConcurrentDataFormatTest {
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint result;
+
+
+ @Test
+ public void testNoConcurrentProducers() throws Exception {
+ doSendMessages(1, 1);
+ }
+
+ @Test
+ public void testConcurrentProducers() throws Exception {
+ doSendMessages(10, 5);
+ }
+
+ private void doSendMessages(int files, int poolSize) throws Exception {
+ result.reset();
+ result.expectedMessageCount(files);
+ result.assertNoDuplicates(body());
+
+ ExecutorService executor = Executors.newFixedThreadPool(poolSize);
+ for (int i = 0; i < files; i++) {
+ final int index = i;
+ executor.submit(new Callable<Object>() {
+ public Object call() throws Exception {
+ PurchaseOrder bean = new PurchaseOrder();
+ bean.setName("Beer");
+ bean.setAmount(Double.valueOf("" + index));
+ bean.setPrice(Double.valueOf("" + index) * 2);
+
+ template.sendBody("direct:start", bean);
+ return null;
+ }
+ });
+ }
+
+ result.assertIsSatisfied();
+ executor.shutdownNow();
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ DataFormat jaxb = new JaxbDataFormat("org.apache.camel.example");
+
+ from("direct:start").marshal(jaxb).to("direct:marshalled");
+
+ from("direct:marshalled").unmarshal(jaxb).to("mock:result");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatMultipleNamespacesTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatMultipleNamespacesTest.java
new file mode 100644
index 0000000..a5ff37a
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatMultipleNamespacesTest.java
@@ -0,0 +1,150 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.bind.JAXBContext;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.Address;
+import org.apache.camel.example.Order;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatMultipleNamespacesTest.class,
+ JaxbDataFormatMultipleNamespacesTest.TestConfiguration.class
+ }
+)
+public class JaxbDataFormatMultipleNamespacesTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JaxbDataFormatMultipleNamespacesTest.class);
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+ @Test
+ public void testMarshallMultipleNamespaces() throws Exception {
+ mockMarshall.expectedMessageCount(1);
+
+ Order order = new Order();
+ order.setId("1");
+ Address address = new Address();
+ address.setStreet("Main Street");
+ address.setStreetNumber("3a");
+ address.setZip("65843");
+ address.setCity("Sulzbach");
+ order.setAddress(address);
+ template.sendBody("direct:marshall", order);
+
+ mockMarshall.assertIsSatisfied();
+
+ String payload = mockMarshall.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(payload);
+
+ assertTrue(payload.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"));
+ assertTrue(payload.contains("<order:order"));
+ assertTrue(payload.contains("<order:id>1</order:id>"));
+ assertTrue(payload.contains("<address:address>"));
+ assertTrue(payload.contains("<address:street>Main Street</address:street>"));
+ assertTrue(payload.contains("<address:streetNumber>3a</address:streetNumber>"));
+ assertTrue(payload.contains("<address:zip>65843</address:zip>"));
+ assertTrue(payload.contains("<address:city>Sulzbach</address:city>"));
+ assertTrue(payload.contains("</address:address>"));
+ assertTrue(payload.contains("</order:order>"));
+
+ // the namespaces
+ assertTrue(payload.contains("xmlns:address=\"http://www.camel.apache.org/jaxb/example/address/1\""));
+ assertTrue(payload.contains("xmlns:order=\"http://www.camel.apache.org/jaxb/example/order/1\""));
+ }
+
+ @Test
+ public void testUnarshallMultipleNamespaces() throws Exception {
+ mockUnmarshall.expectedMessageCount(1);
+
+ String payload
+ = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><ns1:order xmlns:ns2=\"http://www.camel.apache.org/jaxb/example/address/1\""
+ + " xmlns:ns1=\"http://www.camel.apache.org/jaxb/example/order/1\"><ns1:id>1</ns1:id><ns2:address><ns2:street>Main Street</ns2:street>"
+ + "<ns2:streetNumber>3a</ns2:streetNumber><ns2:zip>65843</ns2:zip><ns2:city>Sulzbach</ns2:city></ns2:address></ns1:order>";
+ template.sendBody("direct:unmarshall", payload);
+
+ mockUnmarshall.assertIsSatisfied();
+
+ Order order = (Order) mockUnmarshall.getExchanges().get(0).getIn().getBody();
+ Address address = order.getAddress();
+ assertEquals("1", order.getId());
+ assertEquals("Main Street", address.getStreet());
+ assertEquals("3a", address.getStreetNumber());
+ assertEquals("65843", address.getZip());
+ assertEquals("Sulzbach", address.getCity());
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat(JAXBContext.newInstance(Order.class, Address.class));
+
+ from("direct:marshall")
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+
+ from("direct:unmarshall")
+ .unmarshal(jaxbDataFormat)
+ .to("mock:unmarshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassHeaderTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassHeaderTest.java
new file mode 100644
index 0000000..b98db57
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassHeaderTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.namespace.QName;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbConstants;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.Address;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatPartClassHeaderTest.class,
+ JaxbDataFormatPartClassHeaderTest.TestConfiguration.class
+ }
+)
+public class JaxbDataFormatPartClassHeaderTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JaxbDataFormatPartClassHeaderTest.class);
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+
+
+ @Test
+ public void testMarshallIfPartClassSetInHeaders() throws Exception {
+ mockMarshall.expectedMessageCount(1);
+
+ Address address = new Address();
+ address.setStreet("Main Street");
+ address.setStreetNumber("3a");
+ address.setZip("65843");
+ address.setCity("Sulzbach");
+ template.sendBody("direct:marshall", address);
+
+ mockMarshall.assertIsSatisfied();
+
+ String payload = mockMarshall.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(payload);
+
+ assertTrue(payload.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"));
+ assertTrue(payload.contains("<address:address"));
+ assertTrue(payload.contains("<address:street>Main Street</address:street>"));
+ assertTrue(payload.contains("<address:streetNumber>3a</address:streetNumber>"));
+ assertTrue(payload.contains("<address:zip>65843</address:zip>"));
+ assertTrue(payload.contains("<address:city>Sulzbach</address:city>"));
+ assertTrue(payload.contains("</address:address>"));
+
+ // the namespaces
+ assertTrue(payload.contains("xmlns:address=\"http://www.camel.apache.org/jaxb/example/address/1\""));
+ assertTrue(payload.contains("xmlns:order=\"http://www.camel.apache.org/jaxb/example/order/1\""));
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
+ jaxbDataFormat.setContextPath(Address.class.getPackage().getName());
+ jaxbDataFormat.setPartNamespace(
+ new QName("http://www.camel.apache.org/jaxb/example/address/123", "addressToBeOverriden"));
+ jaxbDataFormat.setPrettyPrint(true);
+
+ from("direct:marshall")
+ .setHeader(JaxbConstants.JAXB_PART_CLASS, simple("org.apache.camel.example.Address"))
+ .setHeader(JaxbConstants.JAXB_PART_NAMESPACE,
+ simple("{http://www.camel.apache.org/jaxb/example/address/1}address"))
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassTest.java
new file mode 100644
index 0000000..a9e8829
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatPartClassTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.namespace.QName;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.Address;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatPartClassTest.class,
+ JaxbDataFormatPartClassTest.TestConfiguration.class
+ }
+)
+public class JaxbDataFormatPartClassTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JaxbDataFormatPartClassTest.class);
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+
+
+
+ @Test
+ public void testMarshallMultipleNamespaces() throws Exception {
+ mockMarshall.expectedMessageCount(1);
+
+ Address address = new Address();
+ address.setStreet("Main Street");
+ address.setStreetNumber("3a");
+ address.setZip("65843");
+ address.setCity("Sulzbach");
+ template.sendBody("direct:marshall", address);
+
+ mockMarshall.assertIsSatisfied();
+
+ String payload = mockMarshall.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(payload);
+
+ assertTrue(payload.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"));
+ assertTrue(payload.contains("<address:address"));
+ assertTrue(payload.contains("<address:street>Main Street</address:street>"));
+ assertTrue(payload.contains("<address:streetNumber>3a</address:streetNumber>"));
+ assertTrue(payload.contains("<address:zip>65843</address:zip>"));
+ assertTrue(payload.contains("<address:city>Sulzbach</address:city>"));
+ assertTrue(payload.contains("</address:address>"));
+
+ // the namespaces
+ assertTrue(payload.contains("xmlns:address=\"http://www.camel.apache.org/jaxb/example/address/1\""));
+ assertTrue(payload.contains("xmlns:order=\"http://www.camel.apache.org/jaxb/example/order/1\""));
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
+ jaxbDataFormat.setContextPath(Address.class.getPackage().getName());
+ jaxbDataFormat.setPartClass(Address.class);
+ jaxbDataFormat.setPartNamespace(new QName("http://www.camel.apache.org/jaxb/example/address/1", "address"));
+ jaxbDataFormat.setPrettyPrint(true);
+
+ from("direct:marshall")
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationTest.java
new file mode 100644
index 0000000..b67f323
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf;
+
+import java.io.IOException;
+
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.converter.jaxb.address.Address;
+import org.apache.camel.converter.jaxb.person.Person;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatSchemaValidationTest.class,
+ JaxbDataFormatSchemaValidationTest.TestConfiguration.class
+ }
+)
+public class JaxbDataFormatSchemaValidationTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JaxbDataFormatSchemaValidationTest.class);
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+
+ @Test
+ public void testMarshallSuccess() throws Exception {
+ mockMarshall.expectedMessageCount(1);
+
+ Address address = new Address();
+ address.setAddressLine1("Hauptstr. 1; 01129 Entenhausen");
+ Person person = new Person();
+ person.setFirstName("Christian");
+ person.setLastName("Mueller");
+ person.setAge(Integer.valueOf(36));
+ person.setAddress(address);
+
+ template.sendBody("direct:marshall", person);
+
+ mockMarshall.assertIsSatisfied();
+
+ String payload = mockMarshall.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(payload);
+
+ assertTrue(payload.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"));
+ assertTrue(payload.contains(
+ "<person xmlns=\"person.jaxb.converter.camel.apache.org\" xmlns:ns2=\"address.jaxb.converter.camel.apache.org\">"));
+ assertTrue(payload.contains("<firstName>Christian</firstName>"));
+ assertTrue(payload.contains("<lastName>Mueller</lastName>"));
+ assertTrue(payload.contains("<age>36</age>"));
+ assertTrue(payload.contains("<address>"));
+ assertTrue(payload.contains("<ns2:addressLine1>Hauptstr. 1; 01129 Entenhausen</ns2:addressLine1>"));
+ assertTrue(payload.contains("</address>"));
+ assertTrue(payload.contains("</person>"));
+ }
+
+ @Test
+ public void testMarshallWithValidationException() {
+ Person person = new Person();
+
+ Exception ex = assertThrows(CamelExecutionException.class,
+ () -> template.sendBody("direct:marshall", person));
+
+ Throwable cause = ex.getCause();
+ assertIsInstanceOf(IOException.class, cause);
+ assertTrue(cause.getMessage().contains("javax.xml.bind.MarshalException"));
+ assertTrue(cause.getMessage().contains("org.xml.sax.SAXParseException"));
+ assertTrue(cause.getMessage().contains("cvc-complex-type.2.4.a"));
+ }
+
+ @Test
+ public void testUnmarshallSuccess() throws Exception {
+ mockUnmarshall.expectedMessageCount(1);
+
+ String xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
+ .append("<person xmlns=\"person.jaxb.converter.camel.apache.org\" xmlns:ns2=\"address.jaxb.converter.camel.apache.org\">")
+ .append("<firstName>Christian</firstName>")
+ .append("<lastName>Mueller</lastName>")
+ .append("<age>36</age>")
+ .append("<address>")
+ .append("<ns2:addressLine1>Hauptstr. 1; 01129 Entenhausen</ns2:addressLine1>")
+ .append("</address>")
+ .append("</person>")
+ .toString();
+ template.sendBody("direct:unmarshall", xml);
+
+ mockUnmarshall.assertIsSatisfied();
+
+ Person person = mockUnmarshall.getExchanges().get(0).getIn().getBody(Person.class);
+
+ assertEquals("Christian", person.getFirstName());
+ assertEquals("Mueller", person.getLastName());
+ assertEquals(Integer.valueOf(36), person.getAge());
+ }
+
+ @Test
+ public void testUnmarshallWithValidationException() throws Exception {
+ String xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
+ .append("<person xmlns=\"person.jaxb.converter.camel.apache.org\" />")
+ .toString();
+
+ Exception ex = assertThrows(CamelExecutionException.class,
+ () -> template.sendBody("direct:unmarshall", xml));
+
+ Throwable cause = ex.getCause();
+ assertIsInstanceOf(IOException.class, cause);
+ assertTrue(cause.getMessage().contains("javax.xml.bind.UnmarshalException"));
+ assertTrue(cause.getMessage().contains("org.xml.sax.SAXParseException"));
+ assertTrue(cause.getMessage().contains("cvc-complex-type.2.4.b"));
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
+ jaxbDataFormat.setContextPath(Person.class.getPackage().getName());
+ jaxbDataFormat.setSchema("classpath:person.xsd,classpath:address.xsd");
+
+ from("direct:marshall")
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+
+ from("direct:unmarshall")
+ .unmarshal(jaxbDataFormat)
+ .to("mock:unmarshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationWithObjectFactoryTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationWithObjectFactoryTest.java
new file mode 100644
index 0000000..292e9ae
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbDataFormatSchemaValidationWithObjectFactoryTest.java
@@ -0,0 +1,153 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.converter.jaxb.message.Message;
+import org.apache.camel.converter.jaxb.message.ObjectFactory;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatSchemaValidationWithObjectFactoryTest.class,
+ JaxbDataFormatSchemaValidationWithObjectFactoryTest.TestConfiguration.class
+ }
+)
+public class JaxbDataFormatSchemaValidationWithObjectFactoryTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:marshall")
+ private MockEndpoint mockMarshall;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+ private JAXBContext jbCtx;
+
+ @BeforeEach
+ public void setUp() throws Exception {
+
+
+ XmlRootElement xmlRootElementAnnotation = Message.class.getAnnotation(XmlRootElement.class);
+ assertNull(xmlRootElementAnnotation);
+
+ jbCtx = JAXBContext.newInstance(Message.class);
+ }
+
+ @Test
+ public void testMarshallOfNonRootElementWithValidationException() {
+ Message message = new Message();
+ Exception ex = Assertions.assertThrows(CamelExecutionException.class,
+ () -> template.sendBody("direct:marshall", message));
+
+ Throwable cause = ex.getCause();
+ assertIsInstanceOf(IOException.class, cause);
+ assertTrue(cause.getMessage().contains("javax.xml.bind.MarshalException"));
+ assertTrue(cause.getMessage().contains("org.xml.sax.SAXParseException"));
+ assertTrue(cause.getMessage().contains("cvc-complex-type.2.4.b"));
+ }
+
+ @Test
+ public void testUnmarshallOfNonRootWithValidationException() throws Exception {
+ JAXBElement<Message> message = new ObjectFactory().createMessage(new Message());
+
+ String xml;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
+ jbCtx.createMarshaller().marshal(message, baos);
+ xml = new String(baos.toByteArray(), "UTF-8");
+ }
+
+ Exception ex = Assertions.assertThrows(CamelExecutionException.class,
+ () -> template.sendBody("direct:unmarshall", xml));
+
+ Throwable cause = ex.getCause();
+ assertIsInstanceOf(IOException.class, cause);
+ assertTrue(cause.getMessage().contains("javax.xml.bind.UnmarshalException"));
+ assertTrue(cause.getMessage().contains("org.xml.sax.SAXParseException"));
+ assertTrue(cause.getMessage().contains("cvc-complex-type.2.4.b"));
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxbDataFormat = new JaxbDataFormat();
+ jaxbDataFormat.setContextPath(Message.class.getPackage().getName());
+ jaxbDataFormat.setSchema("classpath:message.xsd");
+ // if the following is removed the lookup of an object factory method which can create the element
+ // won't be done and the object won'T get marshalled
+ jaxbDataFormat.setObjectFactory(true);
+
+ from("direct:marshall")
+ .marshal(jaxbDataFormat)
+ .to("mock:marshall");
+
+ from("direct:unmarshall")
+ .unmarshal(jaxbDataFormat)
+ .to("mock:unmarshall");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbErrorLogTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbErrorLogTest.java
new file mode 100644
index 0000000..7f42175
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/JaxbErrorLogTest.java
@@ -0,0 +1,148 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.Body;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Handler;
+import org.apache.camel.Message;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbErrorLogTest.class,
+ JaxbErrorLogTest.TestConfiguration.class
+ }
+)
+public class JaxbErrorLogTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:end")
+ private MockEndpoint mock;
+
+
+
+ @Test
+ public void testErrorHandling() throws Exception {
+ // the 2nd message is set to fail, but the 4 others should be routed
+ mock.expectedMessageCount(4);
+
+ // FailingBean will cause message at index 2 to throw exception
+ for (int i = 0; i < 5; i++) {
+ CannotMarshal obj = new CannotMarshal(i);
+ template.send("seda:test", exchange -> {
+ Message in = exchange.getIn();
+ in.setBody(obj);
+ });
+
+ }
+
+ mock.assertIsSatisfied();
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("seda:test")
+ .bean(new FailingBean())
+ .to("log:end", "mock:end");
+ }
+ };
+ }
+ }
+
+ public static final class FailingBean {
+ @Handler
+ public void handle(@Body CannotMarshal body) {
+ if (body.getMessageNo() == 2) {
+ // fail on second message
+ throw new RuntimeCamelException("Kaboom");
+ }
+ }
+ }
+
+ /**
+ * This class will throw RuntimeException on JAXB marshal
+ */
+ @XmlRootElement
+ public static final class CannotMarshal {
+
+ private int messageNo;
+
+ public CannotMarshal() {
+ }
+
+ public CannotMarshal(int messageNo) {
+ this.messageNo = messageNo;
+ }
+
+ public int getMessageNo() {
+ return messageNo;
+ }
+
+ public void setMessageNo(int messageNo) {
+ this.messageNo = messageNo;
+ }
+
+ public void setUhoh(String name) {
+ }
+
+ public String getUhoh() {
+ throw new RuntimeCamelException("Can't marshal this");
+ }
+
+ @Override
+ public String toString() {
+ return "MessageNo. " + messageNo;
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/RouteWithErrorHandlerTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/RouteWithErrorHandlerTest.java
new file mode 100644
index 0000000..592f640
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/RouteWithErrorHandlerTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.InvalidOrderException;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ RouteWithErrorHandlerTest.class,
+ RouteWithErrorHandlerTest.TestConfiguration.class
+ }
+)
+public class RouteWithErrorHandlerTest {
+
+ @Autowired
+ CamelContext context;
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:wine")
+ private MockEndpoint mockWine;
+
+ @EndpointInject("mock:invalid")
+ private MockEndpoint mockInvalid;
+
+ @EndpointInject("mock:result")
+ private MockEndpoint mockResult;
+
+ @EndpointInject("mock:error")
+ private MockEndpoint mockError;
+
+
+ @Test
+ public void testOk() throws Exception {
+ MockEndpoint.resetMocks(context);
+ PurchaseOrder order = new PurchaseOrder();
+ order.setName("Wine");
+ order.setAmount(123.45);
+ order.setPrice(2.22);
+
+
+ mockWine.expectedBodiesReceived(order);
+
+ template.sendBody("direct:start", "<purchaseOrder name='Wine' amount='123.45' price='2.22'/>");
+
+ mockWine.assertIsSatisfied();
+ }
+
+ @Test
+ public void testUnmarshalError() throws Exception {
+ MockEndpoint.resetMocks(context);
+ mockError.expectedMessageCount(1);
+ mockError.message(0).body(String.class).contains("<foo");
+ mockInvalid.expectedMessageCount(0);
+ mockResult.expectedMessageCount(0);
+
+ template.sendBody("direct:start", "<foo/>");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ public void testNotWine() throws Exception {
+ MockEndpoint.resetMocks(context);
+ PurchaseOrder order = new PurchaseOrder();
+ order.setName("Beer");
+ order.setAmount(2);
+ order.setPrice(1.99);
+
+
+ mockInvalid.expectedBodiesReceived(order);
+ mockError.expectedMessageCount(0);
+ mockResult.expectedMessageCount(0);
+
+ template.sendBody("direct:start", "<purchaseOrder name='Beer' amount='2.0' price='1.99'/>");
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+
+ public static boolean isWine(PurchaseOrder order) {
+ return "Wine".equalsIgnoreCase(order.getName());
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ errorHandler(deadLetterChannel("mock:error").redeliveryDelay(0));
+
+ onException(InvalidOrderException.class).maximumRedeliveries(0).handled(true)
+ .to("mock:invalid");
+
+ DataFormat jaxb = new JaxbDataFormat("org.apache.camel.example");
+
+ from("direct:start")
+ .unmarshal(jaxb)
+ .choice()
+ .when().method(RouteWithErrorHandlerTest.class, "isWine").to("mock:wine")
+ .otherwise().throwException(new InvalidOrderException("We only like wine"))
+ .end();
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/TimerBeanToBeanNotificationTypeTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/TimerBeanToBeanNotificationTypeTest.java
new file mode 100644
index 0000000..aa99acf
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/TimerBeanToBeanNotificationTypeTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.jaxb.MyNotificationService;
+import org.apache.camel.jaxb.NotificationType;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ TimerBeanToBeanNotificationTypeTest.class,
+ TimerBeanToBeanNotificationTypeTest.TestConfiguration.class
+ }
+)
+public class TimerBeanToBeanNotificationTypeTest {
+
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:notify")
+ private MockEndpoint notify;
+
+ @Test
+ public void testBeanToBean() throws Exception {
+ notify.expectedMessageCount(1);
+ notify.message(0).body().isInstanceOf(NotificationType.class);
+
+ notify.assertIsSatisfied();
+ }
+
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("timer:foo?delay=500&repeatCount=1")
+ .log("Timer triggered")
+ .bean(MyNotificationService.class, "createNotification")
+ .bean(MyNotificationService.class, "sendNotification");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/UnmarshalTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/UnmarshalTest.java
new file mode 100644
index 0000000..30280d1
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/converter/jaxb/springboot/UnmarshalTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.converter.jaxb.springboot;
+
+
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.example.PurchaseOrder;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.junit.jupiter.api.Test;
+
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ UnmarshalTest.class,
+ UnmarshalTest.TestConfiguration.class
+ }
+)
+public class UnmarshalTest {
+
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint resultEndpoint;
+
+ @EndpointInject("mock:unmarshall")
+ private MockEndpoint mockUnmarshall;
+
+ @Test
+ public void testSendXmlAndUnmarshal() throws Exception {
+ PurchaseOrder expected = new PurchaseOrder();
+ expected.setName("Wine");
+ expected.setAmount(123.45);
+ expected.setPrice(2.22);
+
+ resultEndpoint.expectedBodiesReceived(expected);
+
+ template.sendBody("direct:start", "<purchaseOrder name='Wine' amount='123.45' price='2.22'/>");
+
+ resultEndpoint.assertIsSatisfied();
+ }
+
+ // *************************************
+ // Config
+ // *************************************
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ DataFormat jaxb = new JaxbDataFormat("org.apache.camel.example");
+
+ from("direct:start").unmarshal(jaxb).to("mock:result");
+ }
+ };
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Address.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Address.java
new file mode 100644
index 0000000..6918ef2
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Address.java
@@ -0,0 +1,68 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Address")
+public class Address {
+
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/address/1")
+ private String street;
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/address/1")
+ private String streetNumber;
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/address/1")
+ private String zip;
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/address/1")
+ private String city;
+
+ public String getStreet() {
+ return street;
+ }
+
+ public String getStreetNumber() {
+ return streetNumber;
+ }
+
+ public String getZip() {
+ return zip;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public void setStreetNumber(String streetNumber) {
+ this.streetNumber = streetNumber;
+ }
+
+ public void setZip(String zip) {
+ this.zip = zip;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Bar.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Bar.java
new file mode 100644
index 0000000..d4a42da
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Bar.java
@@ -0,0 +1,52 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Bar {
+
+ @XmlAttribute
+ private String name;
+ @XmlAttribute
+ private String value;
+
+ public Bar() {
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Foo.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Foo.java
new file mode 100644
index 0000000..b91d9f6
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Foo.java
@@ -0,0 +1,43 @@
+/*
+ * 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.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Foo {
+ @XmlElements({
+ @XmlElement(name = "bar", type = Bar.class, required = false),
+ @XmlElement(name = "zot", type = Zot.class, required = false) })
+ List<Bar> barRefs = new ArrayList<>();
+
+ public List<Bar> getBarRefs() {
+ return barRefs;
+ }
+
+ public void setBarRefs(List<Bar> bars) {
+ barRefs = bars;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/InvalidOrderException.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/InvalidOrderException.java
new file mode 100644
index 0000000..8499333
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/InvalidOrderException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.example;
+
+public class InvalidOrderException extends Exception {
+ private static final long serialVersionUID = 383958238537555588L;
+
+ public InvalidOrderException(String message) {
+ super(message);
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Order.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Order.java
new file mode 100644
index 0000000..7d54dcc
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Order.java
@@ -0,0 +1,49 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement(namespace = "http://www.camel.apache.org/jaxb/example/order/1")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Order {
+
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/order/1")
+ private String id;
+
+ @XmlElement(namespace = "http://www.camel.apache.org/jaxb/example/address/1")
+ private Address address;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public Address getAddress() {
+ return address;
+ }
+
+ public void setAddress(Address address) {
+ this.address = address;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Partial.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Partial.java
new file mode 100644
index 0000000..94fa0b7
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Partial.java
@@ -0,0 +1,81 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * Partial element without XmlRootElement annotation for partial testing.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Partial")
+public class Partial {
+
+ @XmlAttribute
+ private String name;
+
+ @XmlElement
+ private String location;
+
+ public final String getName() {
+ return name;
+ }
+
+ public final void setName(String name) {
+ this.name = name;
+ }
+
+ public final String getLocation() {
+ return location;
+ }
+
+ public final void setLocation(String location) {
+ this.location = location;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Partial partial = (Partial) o;
+
+ if (location != null ? !location.equals(partial.location) : partial.location != null) {
+ return false;
+ }
+ if (name != null ? !name.equals(partial.name) : partial.name != null) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = name != null ? name.hashCode() : 0;
+ result = 31 * result + (location != null ? location.hashCode() : 0);
+ return result;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/PurchaseOrder.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/PurchaseOrder.java
new file mode 100644
index 0000000..c3612a3
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/PurchaseOrder.java
@@ -0,0 +1,79 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.util.ObjectHelper;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class PurchaseOrder {
+ @XmlAttribute
+ private String name;
+ @XmlAttribute
+ private double price;
+ @XmlAttribute
+ private double amount;
+
+ @Override
+ public String toString() {
+ return "PurchaseOrder[name: " + name + " amount: " + amount + " price: " + price + "]";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof PurchaseOrder) {
+ PurchaseOrder that = (PurchaseOrder) o;
+ return ObjectHelper.equal(this.name, that.name) && ObjectHelper.equal(this.amount, that.amount)
+ && ObjectHelper.equal(this.price, that.price);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() + (int) Math.round(price * 100) + (int) Math.round(amount * 100);
+ }
+
+ public double getAmount() {
+ return amount;
+ }
+
+ public void setAmount(double amount) {
+ this.amount = amount;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+
+ public void setPrice(double price) {
+ this.price = price;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Zot.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Zot.java
new file mode 100644
index 0000000..cfb62d2
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/Zot.java
@@ -0,0 +1,35 @@
+/*
+ * 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.example;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class Zot extends Bar {
+ private String otherValue;
+
+ public void setOtherValue(String value) {
+ otherValue = value;
+ }
+
+ public String getOtherValue() {
+ return otherValue;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/package-info.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/package-info.java
new file mode 100644
index 0000000..560bb80
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/example/package-info.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+@XmlSchema(
+ xmlns = {
+ @XmlNs(prefix = "order", namespaceURI = "http://www.camel.apache.org/jaxb/example/order/1"),
+ @XmlNs(prefix = "address", namespaceURI = "http://www.camel.apache.org/jaxb/example/address/1")
+ })
+package org.apache.camel.example;
+
+import javax.xml.bind.annotation.XmlNs;
+import javax.xml.bind.annotation.XmlSchema;
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/ObjectFactory.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/ObjectFactory.java
new file mode 100644
index 0000000..dd848b7
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/ObjectFactory.java
@@ -0,0 +1,63 @@
+/*
+ * 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.foo.bar;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElementDecl;
+import javax.xml.bind.annotation.XmlRegistry;
+import javax.xml.namespace.QName;
+
+/**
+ * This object contains factory methods for each Java content interface and Java element interface generated in the
+ * org.apache.camel.foo.bar package.
+ * <p>
+ * An ObjectFactory allows you to programatically construct new instances of the Java representation for XML content.
+ * The Java representation of XML content can consist of schema derived interfaces and classes representing the binding
+ * of schema type definitions, element declarations and model groups. Factory methods for each of these are provided in
+ * this class.
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+ private final QName personQNAME = new QName("", "Person");
+
+ /**
+ * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package:
+ * com.foo.bar
+ *
+ */
+ public ObjectFactory() {
+ }
+
+ /**
+ * Create an instance of {@link PersonType }
+ *
+ */
+ public PersonType createPersonType() {
+ return new PersonType();
+ }
+
+ /**
+ * Create an instance of {@link JAXBElement }{@code <}{@link PersonType }{@code >}}
+ */
+
+ @XmlElementDecl(namespace = "", name = "Person")
+ public JAXBElement<PersonType> createPerson(PersonType value) {
+ return new JAXBElement<>(personQNAME, PersonType.class, null, value);
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/PersonType.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/PersonType.java
new file mode 100644
index 0000000..a78ebc2
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/foo/bar/PersonType.java
@@ -0,0 +1,113 @@
+/*
+ * 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.foo.bar;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.camel.util.ObjectHelper;
+
+/**
+ * <p>
+ * Java class for PersonType complex type.
+ *
+ * <p>
+ * The following schema fragment specifies the expected content contained within this class.
+ *
+ * <pre>
+ * <complexType name="PersonType">
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <sequence>
+ * <element name="firstName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * <element name="lastName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ * </sequence>
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ * </pre>
+ *
+ */
+@XmlRootElement(name = "Person")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "PersonType", propOrder = { "firstName", "lastName" })
+public class PersonType {
+
+ @XmlElement(required = true)
+ protected String firstName;
+ @XmlElement(required = true)
+ protected String lastName;
+
+ /**
+ * Gets the value of the firstName property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getFirstName() {
+ return firstName;
+ }
+
+ /**
+ * Sets the value of the firstName property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setFirstName(String value) {
+ this.firstName = value;
+ }
+
+ /**
+ * Gets the value of the lastName property.
+ *
+ * @return possible object is {@link String }
+ *
+ */
+ public String getLastName() {
+ return lastName;
+ }
+
+ /**
+ * Sets the value of the lastName property.
+ *
+ * @param value allowed object is {@link String }
+ *
+ */
+ public void setLastName(String value) {
+ this.lastName = value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof PersonType) {
+ PersonType that = (PersonType) o;
+ return ObjectHelper.equal(this.firstName, that.firstName)
+ && ObjectHelper.equal(this.lastName, that.lastName);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return firstName.hashCode() + lastName.hashCode() * 100;
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
new file mode 100644
index 0000000..bbc40f0
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbFallbackConverterTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.jaxb;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConversionException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.example.Bar;
+import org.apache.camel.example.Foo;
+import org.apache.camel.foo.bar.PersonType;
+import org.apache.camel.support.DefaultExchange;
+import org.apache.camel.test.junit5.ExchangeTestSupport;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class CamelJaxbFallbackConverterTest extends ExchangeTestSupport {
+
+ @Test
+ public void testFallbackConverterWithoutObjectFactory() throws Exception {
+ TypeConverter converter = context.getTypeConverter();
+ Foo foo = converter.convertTo(Foo.class, exchange,
+ "<foo><zot name=\"bar1\" value=\"value\" otherValue=\"otherValue\"/></foo>");
+ assertNotNull(foo, "foo should not be null");
+ assertEquals("value", foo.getBarRefs().get(0).getValue());
+
+ foo.getBarRefs().clear();
+ Bar bar = new Bar();
+ bar.setName("myName");
+ bar.setValue("myValue");
+ foo.getBarRefs().add(bar);
+
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setProperty(Exchange.CHARSET_NAME, "UTF-8");
+
+ String value = converter.convertTo(String.class, exchange, foo);
+
+ assertTrue(value.indexOf("<bar name=\"myName\" value=\"myValue\"/>") > 0, "Should get a right marshalled string");
+ }
+
+ @Test
+ public void testFallbackConverterUnmarshalWithNonJAXBComplaintValue() throws Exception {
+ TypeConverter converter = context.getTypeConverter();
+
+ try {
+ converter.convertTo(Foo.class, "Not every String is XML");
+ fail("Should have thrown exception");
+ } catch (TypeConversionException e) {
+ // expected
+ }
+
+ try {
+ converter.convertTo(Bar.class, "<bar></bar");
+ fail("Should have thrown exception");
+ } catch (TypeConversionException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testConverter() throws Exception {
+ TypeConverter converter = context.getTypeConverter();
+ PersonType person = converter.convertTo(PersonType.class, exchange,
+ "<Person><firstName>FOO</firstName><lastName>BAR</lastName></Person>");
+ assertNotNull(person, "Person should not be null");
+ assertEquals("FOO", person.getFirstName(), "Get the wrong first name");
+ assertEquals("BAR", person.getLastName(), "Get the wrong second name");
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setProperty(Exchange.CHARSET_NAME, "UTF-8");
+
+ String value = converter.convertTo(String.class, exchange, person);
+ assertTrue(value.indexOf("<lastName>BAR</lastName>") > 0, "Should get a right marshalled string");
+
+ byte[] buffers = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>".getBytes("UTF-8");
+ InputStream is = new ByteArrayInputStream(buffers);
+ try {
+ converter.convertTo(PersonType.class, exchange, is);
+ fail("Should have thrown exception");
+ } catch (TypeConversionException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void testFilteringConverter() throws Exception {
+ byte[] buffers = "<Person><firstName>FOO</firstName><lastName>BAR\u0008</lastName></Person>".getBytes("UTF-8");
+ InputStream is = new ByteArrayInputStream(buffers);
+ Exchange exchange = new DefaultExchange(context);
+ exchange.setProperty(Exchange.CHARSET_NAME, "UTF-8");
+ exchange.setProperty(Exchange.FILTER_NON_XML_CHARS, true);
+ TypeConverter converter = context.getTypeConverter();
+ PersonType person = converter.convertTo(PersonType.class, exchange, is);
+ assertNotNull(person, "Person should not be null ");
+ assertEquals("FOO", person.getFirstName(), "Get the wrong first name");
+ assertEquals("BAR ", person.getLastName(), "Get the wrong second name");
+
+ person.setLastName("BAR\u0008\uD8FF");
+ String value = converter.convertTo(String.class, exchange, person);
+ assertTrue(value.indexOf("<lastName>BAR </lastName>") > 0, "Didn't filter the non-xml chars");
+
+ exchange.setProperty(Exchange.FILTER_NON_XML_CHARS, false);
+
+ value = converter.convertTo(String.class, exchange, person);
+ assertTrue(value.indexOf("<lastName>BAR\uD8FF</lastName>") > 0, "Should not filter the non-xml chars");
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbNoNamespaceSchemaTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbNoNamespaceSchemaTest.java
new file mode 100644
index 0000000..a71dae0
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/CamelJaxbNoNamespaceSchemaTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.jaxb;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.foo.bar.PersonType;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ CamelJaxbNoNamespaceSchemaTest.class
+ }
+)
+public class CamelJaxbNoNamespaceSchemaTest {
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint resultEndpoint;
+
+
+ @Test
+ public void testMarshalWithNoNamespaceSchemaLocation() throws Exception {
+ PersonType person = new PersonType();
+ person.setFirstName("foo");
+ person.setLastName("bar");
+
+
+ resultEndpoint.expectedMessageCount(1);
+ template.sendBody("direct:marshal", person);
+ resultEndpoint.assertIsSatisfied();
+
+ String body = resultEndpoint.getReceivedExchanges().get(0).getIn().getBody(String.class);
+ assertTrue(body.contains("noNamespaceSchemaLocation=\"person-no-namespace.xsd\""),
+ "We should get the noNamespaceSchemaLocation here");
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+
+ public void configure() throws Exception {
+ JaxbDataFormat dataFormat = new JaxbDataFormat("org.apache.camel.foo.bar");
+ dataFormat.setNoNamespaceSchemaLocation("person-no-namespace.xsd");
+ dataFormat.setIgnoreJAXBElement(false);
+
+ from("direct:marshal")
+ .marshal(dataFormat)
+ .to("mock:result");
+
+ }
+ };
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryDisabledTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryDisabledTest.java
new file mode 100644
index 0000000..2a00d8d
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryDisabledTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jaxb;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.FallbackTypeConverter;
+import org.apache.camel.converter.jaxb.message.Message;
+import org.apache.camel.impl.converter.CoreTypeConverterRegistry;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ FallbackTypeConverterObjectFactoryDisabledTest.class
+ }
+)
+public class FallbackTypeConverterObjectFactoryDisabledTest {
+
+ @Autowired
+ ProducerTemplate template;
+
+ @Autowired
+ CamelContext context;
+
+
+ @EndpointInject("mock:a")
+ private MockEndpoint resultEndpoint;
+
+ @Test
+ public void testObjectFactoryFalse() throws Exception {
+ Message in = new Message("Hello World");
+ resultEndpoint.expectedBodiesReceived(in);
+
+ assertThrows(CamelExecutionException.class, () -> template.sendBody("direct:a", in));
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ List<CoreTypeConverterRegistry.FallbackTypeConverter> list = ((CoreTypeConverterRegistry)context.getTypeConverterRegistry()).
+ getFallbackConverters();
+ for (CoreTypeConverterRegistry.FallbackTypeConverter fallback : list) {
+ if (fallback.getFallbackTypeConverter().getClass().getName()
+ .contains("SpringTypeConverter")) {
+ list.remove(fallback);
+ }
+ }
+ context.getGlobalOptions().put(FallbackTypeConverter.OBJECT_FACTORY, "false");
+ return new RouteBuilder(context) {
+
+ @Override
+ public void configure() throws Exception {
+ from("direct:a").convertBodyTo(String.class).to("direct:b");
+ from("direct:b").convertBodyTo(Message.class).to("mock:a");
+ }
+
+ };
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryEnabledTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryEnabledTest.java
new file mode 100644
index 0000000..07bbf9e
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterObjectFactoryEnabledTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.jaxb;
+
+import java.util.List;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.FallbackTypeConverter;
+import org.apache.camel.converter.jaxb.message.Message;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.CamelContextConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.apache.camel.impl.converter.CoreTypeConverterRegistry;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ FallbackTypeConverterObjectFactoryEnabledTest.class,
+ FallbackTypeConverterObjectFactoryEnabledTest.TestConfiguration.class
+ }
+)
+public class FallbackTypeConverterObjectFactoryEnabledTest {
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:a")
+ private MockEndpoint resultEndpoint;
+
+ @Test
+ public void testObjectFactoryTrue() throws Exception {
+
+ Message in = new Message("Hello World");
+ resultEndpoint.expectedBodiesReceived(in);
+
+ template.sendBody("direct:a", in);
+
+ resultEndpoint.assertIsSatisfied();
+ }
+
+
+ @Configuration
+ public class TestConfiguration {
+
+ @Bean
+ public RouteBuilder routeBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ from("direct:a").convertBodyTo(String.class).to("direct:b");
+ from("direct:b").convertBodyTo(Message.class).to("mock:a");
+ }
+ };
+ }
+ }
+
+ @Bean
+ CamelContextConfiguration contextConfiguration() {
+ return new CamelContextConfiguration() {
+ @Override
+ public void beforeApplicationStart(CamelContext context) {
+ //hack way to remove the SpringTypeConverter as its the first fallback converter
+ //but we expect to use the org.apache.camel.converter.jaxb.FallbackTypeConverter
+ //from SimpleTypeConverter in this test case.
+ List<CoreTypeConverterRegistry.FallbackTypeConverter> list = ((CoreTypeConverterRegistry)context.getTypeConverterRegistry()).
+ getFallbackConverters();
+ for (CoreTypeConverterRegistry.FallbackTypeConverter fallback : list) {
+ if (fallback.getFallbackTypeConverter().getClass().getName()
+ .contains("SpringTypeConverter")) {
+ list.remove(fallback);
+ }
+ }
+ context.getGlobalOptions().put(FallbackTypeConverter.OBJECT_FACTORY, "true");
+ }
+ @Override
+ public void afterApplicationStart(CamelContext camelContext) {
+ //do nothing here
+ }
+
+ };
+ }
+
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterShouldThrowExceptionTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterShouldThrowExceptionTest.java
new file mode 100644
index 0000000..0bbc7d6
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/FallbackTypeConverterShouldThrowExceptionTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.jaxb;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.TypeConversionException;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.example.Bar;
+import org.apache.camel.example.Foo;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ FallbackTypeConverterShouldThrowExceptionTest.class
+ }
+)
+public class FallbackTypeConverterShouldThrowExceptionTest {
+
+ private static AtomicInteger failed = new AtomicInteger();
+ private static AtomicInteger failed2 = new AtomicInteger();
+
+ @Autowired
+ ProducerTemplate template;
+
+ @Autowired
+ CamelContext context;
+
+
+ @EndpointInject("mock:a")
+ private MockEndpoint mockA;
+
+ @EndpointInject("mock:b")
+ private MockEndpoint mockB;
+
+ @BeforeEach
+ private void setup() {
+ failed = new AtomicInteger();
+ failed2 = new AtomicInteger();
+ }
+
+ @Test
+ public void testJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object foo = new Foo();
+ mockA.expectedBodiesReceived(foo);
+ mockB.expectedBodiesReceived(foo);
+
+ template.sendBody("direct:a", foo);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(0, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ @Test
+ public void testNoneJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object camel = "Camel";
+ mockA.expectedBodiesReceived(camel);
+ mockB.expectedBodiesReceived(camel);
+
+ template.sendBody("direct:a", camel);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(1, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ @Test
+ public void testAnotherJaxbModel() throws Exception {
+ MockEndpoint.resetMocks(context);
+ Object bar = new Bar();
+ mockA.expectedBodiesReceived(bar);
+ mockB.expectedBodiesReceived(bar);
+
+ template.sendBody("direct:a", bar);
+
+ MockEndpoint.assertIsSatisfied(context);
+
+ assertEquals(1, failed.get());
+ assertEquals(0, failed2.get());
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder(context) {
+
+ @Override
+ public void configure() throws Exception {
+ from("direct:a").process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ try {
+ exchange.getIn().getBody(Foo.class);
+ } catch (TypeConversionException e) {
+ failed.incrementAndGet();
+ }
+ }
+ }).to("mock:a").process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ try {
+ exchange.getIn().getBody(List.class);
+ } catch (TypeConversionException e) {
+ // there is no type converters from the POJO -> List
+ // so we should really not fail at all at this point
+ failed2.incrementAndGet();
+ }
+ }
+
+ }).to("mock:b");
+ }
+
+ };
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatIssueTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatIssueTest.java
new file mode 100644
index 0000000..0ad49ae
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatIssueTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatIssueTest.class
+ }
+)
+public class JaxbDataFormatIssueTest {
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint mock;
+
+
+ @Test
+ public void testJaxbMarshalling() throws InterruptedException {
+ mock.expectedMessageCount(1);
+ mock.message(0).body().endsWith("<foo><bar>Hello Bar</bar></foo>");
+
+ Foo foo = new Foo();
+ foo.setBar("Hello Bar");
+ template.sendBody("direct:start", foo);
+
+ mock.assertIsSatisfied();
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxb = new JaxbDataFormat(JAXBContext.newInstance(Foo.class));
+ jaxb.setPrettyPrint(false);
+
+ from("direct:start").marshal(jaxb).to("log:xml", "mock:result");
+ }
+ };
+ }
+
+ @XmlRootElement
+ public static class Foo {
+ private String bar;
+
+ public String getBar() {
+ return bar;
+ }
+
+ public void setBar(String bar) {
+ this.bar = bar;
+ }
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatMustBeJAXBElementTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatMustBeJAXBElementTest.java
new file mode 100644
index 0000000..352ce3f
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbDataFormatMustBeJAXBElementTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.apache.camel.CamelExecutionException;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.converter.jaxb.JaxbDataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+import static org.apache.camel.test.junit5.TestSupport.assertIsInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbDataFormatMustBeJAXBElementTest.class
+ }
+)
+public class JaxbDataFormatMustBeJAXBElementTest {
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint mock;
+
+ @Test
+ public void testJaxbMarshalling() throws InterruptedException {
+ mock.reset();
+ mock.expectedMessageCount(1);
+ mock.message(0).body().endsWith("<foo><bar>Hello Bar</bar></foo>");
+
+ template.sendBody("direct:start", "<foo><bar>Hello Bar</bar></foo>");
+
+ mock.assertIsSatisfied();
+ }
+
+ @Test
+ public void testJaxbMarshalling2() throws InterruptedException {
+ mock.reset();
+ mock.expectedMessageCount(0);
+
+ try {
+ template.sendBody("direct:start2", "<foo><bar>Hello Bar</bar></foo>");
+ fail("Should have thrown exception");
+ } catch (CamelExecutionException e) {
+ InvalidPayloadException ipe = assertIsInstanceOf(InvalidPayloadException.class, e.getCause().getCause());
+ assertNotNull(ipe);
+ assertEquals(JAXBElement.class, ipe.getType());
+ }
+
+ mock.assertIsSatisfied();
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat jaxb = new JaxbDataFormat(JAXBContext.newInstance(Foo.class));
+ jaxb.setPrettyPrint(false);
+ jaxb.setMustBeJAXBElement(false);
+
+ from("direct:start").marshal(jaxb).to("log:xml", "mock:result");
+
+ JaxbDataFormat jaxb2 = new JaxbDataFormat(JAXBContext.newInstance(Foo.class));
+ jaxb2.setPrettyPrint(false);
+ jaxb2.setMustBeJAXBElement(true);
+
+ from("direct:start2").marshal(jaxb2).to("log:xml", "mock:result2");
+ }
+ };
+ }
+
+ @XmlRootElement
+ public static class Foo {
+ private String bar;
+
+ public String getBar() {
+ return bar;
+ }
+
+ public void setBar(String bar) {
+ this.bar = bar;
+ }
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbMarshalNamespacePrefixMapperTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbMarshalNamespacePrefixMapperTest.java
new file mode 100644
index 0000000..c22dce2
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/JaxbMarshalNamespacePrefixMapperTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.jaxb;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.example.Address;
+import org.apache.camel.example.Order;
+import org.apache.camel.model.dataformat.JaxbDataFormat;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ *
+ */
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ JaxbMarshalNamespacePrefixMapperTest.class
+ }
+)
+public class JaxbMarshalNamespacePrefixMapperTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JaxbMarshalNamespacePrefixMapperTest.class);
+
+ @Autowired
+ ProducerTemplate template;
+
+
+ @EndpointInject("mock:result")
+ private MockEndpoint mock;
+
+ @Bean("myPrefix")
+ public Map<String, String> addMap() throws Exception {
+ Map<String, String> map = new HashMap<>();
+ map.put("http://www.camel.apache.org/jaxb/example/order/1", "o");
+ map.put("http://www.camel.apache.org/jaxb/example/address/1", "a");
+
+ return map;
+ }
+
+ @Test
+ public void testNamespacePrefix() throws Exception {
+ mock.expectedMessageCount(1);
+
+ Order order = new Order();
+ order.setId("1");
+ Address address = new Address();
+ address.setStreet("Main Street");
+ address.setStreetNumber("3a");
+ address.setZip("65843");
+ address.setCity("Sulzbach");
+ order.setAddress(address);
+
+ template.sendBody("direct:start", order);
+
+ mock.assertIsSatisfied();
+
+ String xml = mock.getExchanges().get(0).getIn().getBody(String.class);
+ LOG.info(xml);
+
+ assertTrue(xml.contains("xmlns:a=\"http://www.camel.apache.org/jaxb/example/address/1\""));
+ assertTrue(xml.contains("xmlns:o=\"http://www.camel.apache.org/jaxb/example/order/1\""));
+ assertTrue(xml.contains("<o:id>1</o:id>"));
+ assertTrue(xml.contains("<a:street>Main Street</a:street>"));
+ assertTrue(xml.contains("</o:order>"));
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ JaxbDataFormat df = new JaxbDataFormat();
+ df.setContextPath("org.apache.camel.example");
+ df.setNamespacePrefixRef("myPrefix");
+
+ from("direct:start")
+ .marshal(df)
+ .to("mock:result");
+
+ }
+ };
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyNotificationService.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyNotificationService.java
new file mode 100644
index 0000000..eafb3a9
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyNotificationService.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jaxb;
+
+import org.apache.camel.Exchange;
+
+/**
+ * NotificationType does not have any JAXB ObjectFactory so we should test you can still route using that
+ */
+public class MyNotificationService {
+
+ public void createNotification(Exchange exchange) {
+ NotificationType notification = new NotificationType();
+ notification.setEvent("Hello");
+
+ exchange.getMessage().setBody(notification);
+ }
+
+ public void sendNotification(Exchange exchange) {
+ NotificationType notification = (NotificationType) exchange.getIn().getBody();
+
+ exchange.getContext().createProducerTemplate().sendBody("mock:notify", notification);
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyPersonService.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyPersonService.java
new file mode 100644
index 0000000..d80d6f0
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/MyPersonService.java
@@ -0,0 +1,41 @@
+/*
+ * 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.jaxb;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.foo.bar.PersonType;
+
+/**
+ *
+ */
+public class MyPersonService {
+
+ public void createPerson(Exchange exchange) {
+ PersonType person = new PersonType();
+ person.setFirstName("Homer");
+ person.setLastName("Simpson");
+
+ exchange.getMessage().setBody(person);
+ }
+
+ public void sendPerson(Exchange exchange) {
+ PersonType person = (PersonType) exchange.getIn().getBody();
+
+ exchange.getContext().createProducerTemplate().sendBody("mock:person", person);
+ }
+
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/NotificationType.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/NotificationType.java
new file mode 100644
index 0000000..4e92756
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/NotificationType.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+@XmlRootElement(name = "Notification")
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "NotificationType", propOrder = { "event" })
+public class NotificationType {
+ @XmlElement(required = true)
+ protected String event;
+
+ public String getEvent() {
+ return event;
+ }
+
+ public void setEvent(String event) {
+ this.event = event;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/SplitterAndExceptionRouteTwistIssueTest.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/SplitterAndExceptionRouteTwistIssueTest.java
new file mode 100644
index 0000000..950cd36
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/SplitterAndExceptionRouteTwistIssueTest.java
@@ -0,0 +1,223 @@
+/*
+ * 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.jaxb;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Exchange;
+import org.apache.camel.LoggingLevel;
+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.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.test.spring.junit5.CamelSpringBootTest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.annotation.Bean;
+import org.springframework.test.annotation.DirtiesContext;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ */
+
+@DirtiesContext
+@CamelSpringBootTest
+@SpringBootTest(
+ classes = {
+ CamelAutoConfiguration.class,
+ SplitterAndExceptionRouteTwistIssueTest.class
+ }
+)
+
+public class SplitterAndExceptionRouteTwistIssueTest {
+
+ @Autowired
+ CamelContext context;
+
+ @Produce("direct:error")
+ protected ProducerTemplate templateError;
+
+ @Produce("direct:error2")
+ protected ProducerTemplate templateError2;
+
+ @EndpointInject("mock:mockReject")
+ protected MockEndpoint mockRejectEndpoint;
+
+ @EndpointInject("mock:mock_output")
+ protected MockEndpoint mockOutput;
+
+ @Test
+ public void testErrorHandlingJaxb() throws Exception {
+ MockEndpoint.resetMocks(context);
+ String correctExample = "abcdef";
+ String errorExample = "myerror\u0010";
+
+ mockRejectEndpoint.expectedMessageCount(1);
+ mockOutput.expectedMessageCount(4);
+
+ templateError.sendBody(correctExample);
+ templateError.sendBody(errorExample);
+ templateError.sendBody(correctExample);
+ templateError.sendBody(correctExample);
+ templateError.sendBody(correctExample);
+
+ mockRejectEndpoint.assertIsSatisfied();
+ mockOutput.assertIsSatisfied();
+ }
+
+ @Test
+ public void testErrorHandlingPlumber() throws Exception {
+ MockEndpoint.resetMocks(context);
+ String correctExample = "abcdef";
+ String errorExample = "myerror\u0010";
+
+ mockRejectEndpoint.expectedMessageCount(1);
+ mockOutput.expectedMessageCount(4);
+
+ templateError2.sendBody(correctExample);
+ templateError2.sendBody(errorExample);
+ templateError2.sendBody(correctExample);
+ templateError2.sendBody(correctExample);
+ templateError2.sendBody(correctExample);
+
+ mockRejectEndpoint.assertIsSatisfied();
+ mockOutput.assertIsSatisfied();
+ }
+
+ @Bean
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+
+ @Override
+ public void configure() throws Exception {
+
+ errorHandler(
+ deadLetterChannel(mockRejectEndpoint)
+ .useOriginalMessage()
+ .maximumRedeliveries(0)
+ .retryAttemptedLogLevel(LoggingLevel.WARN)
+ .logExhausted(true)
+ .logStackTrace(true)
+ .logRetryStackTrace(true));
+
+ from("direct:error")
+ .convertBodyTo(String.class, "UTF-8")
+ .process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ String text = (String) exchange.getIn().getBody();
+ Twits twits = new Twits();
+
+ Twit twit1 = new Twit();
+ twit1.setText(text);
+ twits.getTwits().add(twit1);
+
+ exchange.getIn().setBody(twits);
+ }
+ })
+ .split().xpath("//twits/twit").streaming()
+ .to(mockOutput);
+
+ from("direct:error2")
+ .convertBodyTo(String.class, "UTF-8")
+ .process(new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ String text = (String) exchange.getIn().getBody();
+
+ StringBuilder twits = new StringBuilder();
+ twits.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
+
+ twits.append("<twits>");
+ twits.append("<twit>");
+ twits.append(text);
+ twits.append("</twit>");
+ twits.append("</twits>");
+
+ exchange.getIn().setBody(twits.toString());
+ }
+ })
+ .split().xpath("//twits/twit").streaming()
+ .to(mockOutput);
+ }
+ };
+ }
+}
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = { "twits" })
+@XmlRootElement(name = "twits")
+class Twits implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(name = "twit", required = true)
+ protected List<Twit> twits;
+
+ public List<Twit> getTwits() {
+ if (twits == null) {
+ twits = new ArrayList<>();
+ }
+ return this.twits;
+ }
+
+ @Override
+ public String toString() {
+ if (twits == null || twits.isEmpty()) {
+ return super.toString();
+ }
+ return super.toString() + "[" + twits.get(0).toString() + "]";
+ }
+}
+
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "Twit", propOrder = { "text" })
+@XmlRootElement(name = "twit")
+class Twit implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @XmlElement(required = true)
+ protected String text;
+
+ public String getText() {
+ return text;
+ }
+
+ public void setText(String value) {
+ this.text = value;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/TestXmlStreamWriter.java b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/TestXmlStreamWriter.java
new file mode 100644
index 0000000..37151a9
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/java/org/apache/camel/jaxb/TestXmlStreamWriter.java
@@ -0,0 +1,190 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import org.apache.camel.converter.jaxb.JaxbXmlStreamWriterWrapper;
+
+public class TestXmlStreamWriter implements JaxbXmlStreamWriterWrapper {
+ @Override
+ public XMLStreamWriter wrapWriter(final XMLStreamWriter writer) {
+ return new XMLStreamWriter() {
+ @Override
+ public void writeStartElement(String s) throws XMLStreamException {
+ writer.writeStartElement(s + "-Foo");
+ }
+
+ @Override
+ public void writeStartElement(String s, String s2) throws XMLStreamException {
+ writer.writeStartElement(s, s2 + "-Foo");
+ }
+
+ @Override
+ public void writeStartElement(String s, String s2, String s3) throws XMLStreamException {
+ writer.writeStartElement(s, s2 + "-Foo", s3);
+ }
+
+ @Override
+ public void writeEmptyElement(String s, String s2) throws XMLStreamException {
+ writer.writeEmptyElement(s, s2);
+ }
+
+ @Override
+ public void writeEmptyElement(String s, String s2, String s3) throws XMLStreamException {
+ writer.writeEmptyElement(s, s2, s3);
+ }
+
+ @Override
+ public void writeEmptyElement(String s) throws XMLStreamException {
+ writer.writeEmptyElement(s);
+ }
+
+ @Override
+ public void writeEndElement() throws XMLStreamException {
+ writer.writeEndElement();
+ }
+
+ @Override
+ public void writeEndDocument() throws XMLStreamException {
+ writer.writeEndDocument();
+ }
+
+ @Override
+ public void close() throws XMLStreamException {
+ writer.close();
+ }
+
+ @Override
+ public void flush() throws XMLStreamException {
+ writer.flush();
+ }
+
+ @Override
+ public void writeAttribute(String s, String s2) throws XMLStreamException {
+ writer.writeAttribute(s, s2);
+ }
+
+ @Override
+ public void writeAttribute(String s, String s2, String s3, String s4) throws XMLStreamException {
+ writer.writeAttribute(s, s2, s3, s4);
+ }
+
+ @Override
+ public void writeAttribute(String s, String s2, String s3) throws XMLStreamException {
+ writer.writeAttribute(s, s2, s3);
+ }
+
+ @Override
+ public void writeNamespace(String s, String s2) throws XMLStreamException {
+ writer.writeNamespace(s, s2);
+ }
+
+ @Override
+ public void writeDefaultNamespace(String s) throws XMLStreamException {
+ writer.writeDefaultNamespace(s);
+ }
+
+ @Override
+ public void writeComment(String s) throws XMLStreamException {
+ writer.writeComment(s);
+ }
+
+ @Override
+ public void writeProcessingInstruction(String s) throws XMLStreamException {
+ writer.writeProcessingInstruction(s);
+ }
+
+ @Override
+ public void writeProcessingInstruction(String s, String s2) throws XMLStreamException {
+ writer.writeProcessingInstruction(s, s2);
+ }
+
+ @Override
+ public void writeCData(String s) throws XMLStreamException {
+ writer.writeCData(s);
+ }
+
+ @Override
+ public void writeDTD(String s) throws XMLStreamException {
+ writer.writeDTD(s);
+ }
+
+ @Override
+ public void writeEntityRef(String s) throws XMLStreamException {
+ writer.writeEntityRef(s);
+ }
+
+ @Override
+ public void writeStartDocument() throws XMLStreamException {
+ writer.writeStartDocument();
+ }
+
+ @Override
+ public void writeStartDocument(String s) throws XMLStreamException {
+ writer.writeStartDocument(s);
+ }
+
+ @Override
+ public void writeStartDocument(String s, String s2) throws XMLStreamException {
+ writer.writeStartDocument(s, s2);
+ }
+
+ @Override
+ public void writeCharacters(String s) throws XMLStreamException {
+ writer.writeCharacters(s);
+ }
+
+ @Override
+ public void writeCharacters(char[] chars, int i, int i2) throws XMLStreamException {
+ writer.writeCharacters(chars, i, i2);
+ }
+
+ @Override
+ public String getPrefix(String s) throws XMLStreamException {
+ return writer.getPrefix(s);
+ }
+
+ @Override
+ public void setPrefix(String s, String s2) throws XMLStreamException {
+ writer.setPrefix(s, s2);
+ }
+
+ @Override
+ public void setDefaultNamespace(String s) throws XMLStreamException {
+ writer.setDefaultNamespace(s);
+ }
+
+ @Override
+ public void setNamespaceContext(NamespaceContext namespaceContext) throws XMLStreamException {
+ writer.setNamespaceContext(namespaceContext);
+ }
+
+ @Override
+ public NamespaceContext getNamespaceContext() {
+ return writer.getNamespaceContext();
+ }
+
+ @Override
+ public Object getProperty(String s) throws IllegalArgumentException {
+ return writer.getProperty(s);
+ }
+ }; //To change body of implemented methods use File | Settings | File Templates.
+ }
+}
diff --git a/components-starter/camel-jaxb-starter/src/test/resources/address.xsd b/components-starter/camel-jaxb-starter/src/test/resources/address.xsd
new file mode 100644
index 0000000..3cc6cef
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/resources/address.xsd
@@ -0,0 +1,32 @@
+<?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.
+
+-->
+<xs:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:p="org.person"
+ targetNamespace="address.jaxb.converter.camel.apache.org">
+
+ <xs:complexType name="address">
+ <xs:sequence>
+ <xs:element name="addressLine1" type="xs:string" minOccurs="1" />
+ <xs:element name="addressLine2" type="xs:string" minOccurs="0"/>
+ </xs:sequence>
+ </xs:complexType>
+</xs:schema>
\ No newline at end of file
diff --git a/components-starter/camel-jaxb-starter/src/test/resources/message.xml b/components-starter/camel-jaxb-starter/src/test/resources/message.xml
new file mode 100644
index 0000000..6afe321
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/resources/message.xml
@@ -0,0 +1,22 @@
+<?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.
+
+-->
+<tns:message xmlns:tns="address.jaxb.converter.camel.apache.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="address.jaxb.converter.camel.apache.org message.xsd ">
+ <tns:text>tns:text</tns:text>
+</tns:message>
diff --git a/components-starter/camel-jaxb-starter/src/test/resources/message.xsd b/components-starter/camel-jaxb-starter/src/test/resources/message.xsd
new file mode 100644
index 0000000..a7c0a6d
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/resources/message.xsd
@@ -0,0 +1,32 @@
+<?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.
+
+-->
+<schema xmlns="http://www.w3.org/2001/XMLSchema"
+ targetNamespace="message.jaxb.converter.camel.apache.org"
+ xmlns:tns="message.jaxb.converter.camel.apache.org"
+ elementFormDefault="qualified">
+
+ <element name="message" type="tns:Message"></element>
+
+ <complexType name="Message">
+ <sequence>
+ <element name="text" minOccurs="1" type="string" />
+ </sequence>
+ </complexType>
+</schema>
\ No newline at end of file
diff --git a/components-starter/camel-jaxb-starter/src/test/resources/org/apache/camel/example/jaxb.index b/components-starter/camel-jaxb-starter/src/test/resources/org/apache/camel/example/jaxb.index
new file mode 100644
index 0000000..39a554c
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/resources/org/apache/camel/example/jaxb.index
@@ -0,0 +1,23 @@
+## ------------------------------------------------------------------------
+## 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.
+## ------------------------------------------------------------------------
+Address
+Order
+PurchaseOrder
+Partial
+Foo
+Bar
+Zot
\ No newline at end of file
diff --git a/components-starter/camel-jaxb-starter/src/test/resources/person.xsd b/components-starter/camel-jaxb-starter/src/test/resources/person.xsd
new file mode 100644
index 0000000..2413511
--- /dev/null
+++ b/components-starter/camel-jaxb-starter/src/test/resources/person.xsd
@@ -0,0 +1,38 @@
+<?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.
+
+-->
+<xs:schema attributeFormDefault="unqualified"
+ elementFormDefault="qualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:a="address.jaxb.converter.camel.apache.org"
+ targetNamespace="person.jaxb.converter.camel.apache.org">
+
+ <xs:import schemaLocation="address.xsd" namespace="address.jaxb.converter.camel.apache.org" />
+
+ <xs:element name="person">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="firstName" type="xs:string" minOccurs="1" />
+ <xs:element name="lastName" type="xs:string" minOccurs="1"/>
+ <xs:element name="age" type="xs:int" nillable="true" minOccurs="1"/>
+ <xs:element name="address" type="a:address" minOccurs="1" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
\ No newline at end of file