The type conversion mechanism can easily be customized by adding a new slave type converter. This section describes how to implement a slave type converter and how to integrate it with Fuse Mediation Router, so that it is automatically loaded by the annotation type converter loader.
You can implement a custom type converter class using the @Converter
annotation. You must annotate the class itself and each of the
static
methods intended to perform type conversion. Each converter method
takes an argument that defines the from type, optionally takes a second
Exchange
argument, and has a non-void return value that defines the
to type. The type converter loader uses Java reflection to find the
annotated methods and integrate them into the type converter mechanism. Example 3.3 shows an example of an annotated converter class that
defines a converter method for converting from java.io.File
to
java.io.InputStream
and another converter method (with an
Exchange
argument) for converting from byte[]
to
String
.
Example 3.3. Example of an Annotated Converter Class
package com.YourDomain
.YourPackageName
; import org.apache.camel.Converter; import java.io.*; @Converter public class IOConverter { private IOConverter() { } @Converter public static InputStream toInputStream(File file) throws FileNotFoundException { return new BufferedInputStream(new FileInputStream(file)); } @Converter public static String toString(byte[] data, Exchange exchange) { if (exchange != null) { String charsetName = exchange.getProperty(Exchange.CHARSET_NAME, String.class); if (charsetName != null) { try { return new String(data, charsetName); } catch (UnsupportedEncodingException e) { LOG.warn("Can't convert the byte to String with the charset " + charsetName, e); } } } return new String(data); } }
The toInputStream()
method is responsible for
performing the conversion from the File
type to the InputStream
type and the toString()
method is responsible for performing the conversion
from the byte[]
type to the String
type.
![]() | Note |
---|---|
The method name is unimportant, and can be anything you choose. What is important are
the argument type, the return type, and the presence of the |
To enable the discovery mechanism (which is implemented by the annotation
type converter loader) for your custom converter, create a
TypeConverter
file at the following
location:
META-INF/services/org/apache/camel/TypeConverter
The
TypeConverter
file must contain a comma-separated list of package
names identifying the packages that contain type converter classes. For example, if you want
the type converter loader to search the
com.
YourDomain
.
YourPackageName
package for annotated converter classes, the TypeConverter
file would
have the following
contents:
com.YourDomain
.YourPackageName
The type converter is packaged as a JAR file containing the compiled classes of your
custom type converters and the META-INF
directory.
Put this JAR file on your classpath to make it available to your Fuse Mediation Router
application.
In addition to defining regular converter methods using the @Converter
annotation, you can optionally define a fallback converter method using the
@FallbackConverter
annotation. The fallback converter method will only be
tried, if the master type converter fails to find a regular converter method in the type
registry.
The essential difference between a regular converter method and a fallback converter
method is that whereas a regular converter is defined to perform conversion between a
specific pair of types (for example, from byte[]
to String
), a
fallback converter can potentially perform conversion between any pair
of types. It is up to the code in the body of the fallback converter method to figure out
which conversions it is able to perform. At run time, if a conversion cannot be performed
by a regular converter, the master type converter iterates through every available fallback
converter until it finds one that can perform the conversion.
The method signature of a fallback converter can have either of the following forms:
// 1. Non-generic form of signature @FallbackConverter public static ObjectMethodName
( Class type, Exchange exchange, Object value, TypeConverterRegistry registry ) // 2. Templating form of signature @FallbackConverter public static <T> TMethodName
( Class<T> type, Exchange exchange, Object value, TypeConverterRegistry registry )
Where MethodName
is an arbitrary method name for the fallback
converter.
For example, the following code extract (taken from the implementation of the File
component) shows a fallback converter that can convert the body of a
GenericFile
object, exploiting the type converters already available in the
type converter registry:
package org.apache.camel.component.file; import org.apache.camel.Converter; import org.apache.camel.FallbackConverter; import org.apache.camel.Exchange; import org.apache.camel.TypeConverter; import org.apache.camel.spi.TypeConverterRegistry; @Converter public final class GenericFileConverter { private GenericFileConverter() { // Helper Class } @FallbackConverter public static <T> T convertTo(Class<T> type, Exchange exchange, Object value, TypeConverterRegistry registry) { // use a fallback type converter so we can convert the embedded body if the value is GenericFile if (GenericFile.class.isAssignableFrom(value.getClass())) { GenericFile file = (GenericFile) value; Class from = file.getBody().getClass(); TypeConverter tc = registry.lookup(type, from); if (tc != null) { Object body = file.getBody(); return tc.convertTo(type, exchange, body); } } return null; } ... }