4

In order to marshal jaxb classes with Apache Camel the jaxb class needs to include a XmlRootElement annotation.

When generating jaxb classes from XSD the XmlRootElement annotation might not be generated.

This will lead to an Exception during marshalling "No type converter available to convert from type: "

As soon as I add the @XmlRootElement manually, everything works fine, but since these Jaxb classes are generated, adding the anntotation manually is no option.

According to the Camel documentation in such a case, the JaxbDataFormat can be set to 'fragement(true)

JaxbDataFormat jaxbMarshal = new JaxbDataFormat();
jaxbMarshal.setContextPath(ObjectFactory.class.getPackage().getName());
jaxbMarshal.setFragment(true);

Unfortunately I still get the same exception.

Is there a way to configure JaxbDataFormat different, i.e. to define the JAXBElement which is the root element, like I would do in Java

marshaller.marshal( new JAXBElement( new QName("uri","local"),
   MessageType.class, messageType ));

or is there another strategy available to get the XML marshalled?

EDIT the used route :

 from("file://inbox").unmarshal(jaxbDataFormat)
.marshal(jaxbDataFormat).to("file://outbox");

the stacktrace:

java.io.IOException: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: com.xyz.AddressType to the required type: java.io.InputStream with value com.xyz.AddressType@32317e9d at org.apache.camel.converter.jaxb.JaxbDataFormat.marshal(JaxbDataFormat.java:148) ~[camel-jaxb-2.16.0.jar:2.16.0] at org.apache.camel.processor.MarshalProcessor.process(MarshalProcessor.java:83) ~[camel-core-2.16.0.jar:2.16.0] at

...

[na:1.8.0_25] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25] Caused by: org.apache.camel.NoTypeConversionAvailableException: No type converter available to convert from type: com.xyz.AddressType to the required type: java.io.InputStream with value com.xyz.AddressType@32317e9d at org.apache.camel.impl.converter.BaseTypeConverterRegistry.mandatoryConvertTo(BaseTypeConverterRegistry.java:185) ~[camel-core-2.16.0.jar:2.16.0] at

...

ABX
  • 1,173
  • 2
  • 22
  • 39

4 Answers4

2

In Camel 2.17, the @XmlRootElement was not required. As of 2.21, it is. Unless...

The class org.apache.camel.converter.jaxb.FallBackTypeConverter changed it's implementation from:

protected <T> boolean isJaxbType(Class<T> type) {
    return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
}

To:

protected <T> boolean isJaxbType(Class<T> type) {
    if (isObjectFactory()) {
        return hasXmlRootElement(type) || JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) != null;
    } else {
        return hasXmlRootElement(type);
    }
}

By default the isObjectFactory() method returns false. If you set the property CamelJaxbObjectFactoryon your CamelContext to true. then the JaxbHelper.getJaxbElementFactoryMethod(camelContext, type) will return true and the deserialization works again as before without the need for an @XmlRootElement. For completeness:

<camelContext xmlns="http://camel.apache.org/schema/spring" id="camelContext">
    <properties>
        <property key="CamelJaxbObjectFactory" value="true"/>
    </properties>
</camelContext>
Maarten
  • 808
  • 1
  • 6
  • 17
1

I experienced the equivalent behaviour with JaxB (@XmlRootElement annotation not present in the generated class), and I suppose it comes from the way the root element is defined in the XML schema.

For example:

<xsd:element name="DiffReport" type="DiffReportType" />
<xsd:complexType name="DiffReportType">
    ...
</xsd:complexType>

it will generate you the DiffReportType class without the @XmlRootElement annotation. But if you directly define your root element as following, you'll get the annotation set in your generated class (the name of the root class is then DiffReport in my example).

<xsd:element name="DiffReport">
    <xsd:complexType>
        ...

Note: I used the first way to define the complex types in my schema for class name consistency.

Loic Mouchard
  • 1,121
  • 7
  • 22
  • Yes You're right, that will create the @XmlRootElement. Unfortunately I cannot change the XSD. It is already heavily used by the application. I need a solution to handle the Jaxb classes without the root element. Anyway thank You for the info. – ABX Mar 07 '16 at 19:10
  • Have a look to a related question: http://stackoverflow.com/questions/819720/no-xmlrootelement-generated-by-jaxb – Loic Mouchard Mar 08 '16 at 07:39
0

You can use the "partClass" option of the jaxb data format of camel. Your question is answered in the camel docs for jaxb, which describes how to marshall XML fragments (or XML generated without the XmlRootElement annotation).

Steve Harrington
  • 942
  • 1
  • 7
  • 18
0

Use partClass and provide the actual class name to which you wish to marshall. In case of marshalling you also have to provide the partNamespace which is the target namespace of the desired XML object.

Fairy
  • 3,592
  • 2
  • 27
  • 36
Gogol
  • 1,624
  • 1
  • 13
  • 10