Question

I am using Apache Camel 2.9.2 and Spring 3.0.6.RELEASE. I am trying to use a custom DataFormat to marshal and unmarshal Camel messages. I want to configure my custom DataFormat into one of my routes using Spring.

Apache Camel's documentation states that in order to hook up my custom Data Format to a route in Spring I simply need to declare my custom DataFormat as a bean and reference it inside of my Spring route like so:

<marshal>
    <custom ref="myCustomDataFormat"/>
</marshal>

http://camel.apache.org/custom-dataformat.html

So I have the following setup:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-3.0.xsd
">

<bean id="myCustomDataFormat" class="com.test.CustomDataFormat"/>
<!-- Camel Context -->
<camelContext xmlns="http://camel.apache.org/schema/spring">
    <route>
        <from uri="file:C:/test?initialDelay=4000&amp;delay=1000"/>
        <marshal>
            <custom ref="myCustomDataFormat"/>
        </marshal>
        <to uri="file:C:/test2"/>
    </route>
</camelContext>
</beans>

But when I try to start Camel, I get the following nasty error:

org.springframework.beans.ConversionNotSupportedException: Failed to convert value of type 'com.test.CustomDataFormat' to required type 'org.apache.camel.model.DataFormatDefinition'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.test.CustomDataFormat] to required type [org.apache.camel.model.DataFormatDefinition]: no matching editors or conversion strategy found

My Data Format is defined as follows:

package com.test;

import java.io.InputStream;
import java.io.OutputStream;

import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;

public class CustomDataFormat implements DataFormat {

/* (non-Javadoc)
 * @see org.apache.camel.spi.DataFormat#marshal(org.apache.camel.Exchange, java.lang.Object, java.io.OutputStream)
 */
@Override
public void marshal(Exchange exchange, Object graph, OutputStream stream)
        throws Exception {
    System.out.println("Marshal");
    byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, graph);
    stream.write(bytes);

}

/* (non-Javadoc)
 * @see org.apache.camel.spi.DataFormat#unmarshal(org.apache.camel.Exchange, java.io.InputStream)
 */
@Override
public Object unmarshal(Exchange exchange, InputStream stream)
        throws Exception {
    System.out.println("Unmarshal");
    byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, stream);
    return bytes;
}
}

I know that my CustomDataFormat implementation is correct because I created the following test route in Java and it worked flawlessly

package com.test;

import org.apache.camel.spring.SpringRouteBuilder;

public class TestFormatRoute extends SpringRouteBuilder {

/* (non-Javadoc)
 * @see org.apache.camel.builder.RouteBuilder#configure()
 */
@Override
public void configure() throws Exception {
    from("file:C:/test?initialDelay=4000&delay=1000").unmarshal(new CustomDataFormat()).to("file:C:/test2");
}

}

What am I missing?

Thanks

Update

After letting Camel completely start up after receiving this error I found to my disbelief that my custom data format actually does work in the route that I created. I'm not sure what process is attempting to parse my custom data format and failing but it is apparently not the same process parsing the data format to put into my route.

This solves the functional requirement of the data format, but it does not explain why I am receiving this error.

I have also confirmed that it was not the name of my data format (CustomDataFormat) that was causing the issue. Renaming my DataFormat to a unique name (MerlinDataFormat) did not fix the error.

I still would like to know why I am receiving this error since large blocks of ugly red errors in my console and log files aren't exactly appealing.

Thanks again.

Was it helpful?

Solution

It turned out to be a pretty simple solution (and one that I admit should have been easy to see). There are actually two ways to go about solving this issue, one of them using only spring and one of them requiring an additional java class.

Solution 1

Create a new class extending DataFormatDefinition which has the same properties as your custom DataFormat. Override the configureDataFormat() method to set all of the properties of the underlying DataFormat. Add constructor(s) to set the underlying DataFormat as an instance of your CustomDataFormat. Now you should be able to create an instance of your DataFormatDefinition in spring and reference it when marshaling or unmarshaling.

Solution 2 (Quick & Dirty)

In spring, create a new DataFormatDefinition bean and set it's dataFormat property as a reference to your DataFormat spring bean. Now you should be able to reference your DataFormatDefinition bean when marshaling or unmarshaling.

OTHER TIPS

Not really sure what's wrong with your example, it seems just fine. Can you post your code for the data format? Are you implementing org.apache.camel.spi.DataFormat correctly?

I just set up this example with Camel 2.9.2 and it works like a charm. The Custom data format is the one from Camel documentation/source code.

<bean id="mySweetDf" class="com.example.MySweetDf"/>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<route>
        <from uri="file:C:/temp/test?initialDelay=4000&amp;delay=1000"/>
        <marshal>
            <custom ref="mySweetDf"/>
        </marshal>
        <convertBodyTo type="java.lang.String"/>
        <to uri="file:C:/temp/test2"/>
    </route>
</camelContext>

data format java file:

package com.example;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.camel.Exchange;
import org.apache.camel.spi.DataFormat;

public class MySweetDf implements DataFormat {

  public void marshal(Exchange exchange, Object graph, OutputStream stream) throws Exception {
    byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, graph);
    String body = reverseBytes(bytes);
    stream.write(body.getBytes());
}

  public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
    byte[] bytes = exchange.getContext().getTypeConverter().mandatoryConvertTo(byte[].class, stream);
    String body = reverseBytes(bytes);
    return body;
}

  private String reverseBytes(byte[] data) {
    StringBuilder sb = new StringBuilder(data.length);
    for (int i = data.length - 1; i >= 0; i--) {
        char ch = (char) data[i];
        sb.append(ch);
    }
    return sb.toString();
}
}

UPDATE

Just tried you code. Seems to work as well. Created a fresh camel 2.9.2 project via mvn archetype 168: remote -> org.apache.camel.archetypes:camel-archetype-spring (Creates a new Camel project with added Spring DSL support.). This does only include camel-core and camel-spring dependencies, nothing else.

Then replaced camel-context.xml with your xml and added your data format code in the java directory. A run with "mvn camel:run" copied the file and printed "marshal" in the log.

[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Route: route1 started and consuming from: Endpoint[file://C:/test?delay=1000&initialDelay=4000]
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Total 1 routes, of which 1 is started.
[pache.camel.spring.Main.main()] SpringCamelContext             INFO  Apache Camel 2.9.2 (CamelContext: camel-1) started in 0.808 seconds
Marshal

Are you sure you have all dependencies setup correctly and not some .jar file that messes things up with Data formats?

UPDATE2

Okay, I think I have an idea what it is:

http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/model/dataformat/CustomDataFormat.html Camel already have a class named as your data format. You should try rename it to something else. CustomDataFormat extends org.apache.camel.model.DataFormatDefinition which is referred to in your error. Java should handle this, since it's two different namespaces, but there might be some issue in your project setup that causes this conflict. Try to rename the data format and see if that solves the problem.

I too was facing the same issue with camel 2.10.0. If you provide the ref with an instance of type org.apache.camel.model.DataFormatDefinition everything works fine!! I can see two classes for xmljson conversion --> XmlJsonDataFormat implementing both DataFormat and DataFormatDefinition.

I solved the same issue that I too was facing. Implemented a class extending DataFormatDefintion - which in it's configureDataFormat method sets injectable properties for the class that extends DataFormat (in your case this is CustomDataFormat). I used XmlJson conversion as a template to solve.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top