36.3. アノテーションを使用した型コンバーターの実装
概要
型変換メカニズムは、新しい Slave 型コンバーターを追加することで簡単にカスタマイズできます。ここでは、Slave 型コンバーターの実装方法と、アノテーション型コンバーターローダーによって自動的にロードされるように Apache Camel と統合する方法を説明します。
型コンバーターの実装方法
アノテーションが付けられたコンバータークラスの実装
@Converter
アノテーションを使用してカスタム型コンバータークラスを実装できます。クラス自体にアノテーションを付け、型変換を実行する各 static
メソッドにもアノテーションを付ける必要があります。各コンバーターメソッドは from 型を定義する引数を取り、オプションで 2 番目の Exchange
引数を取り、 to 型を定義する void でない戻り値を持ちます。型コンバーターローダーは Java リフレクションを使用してアノテーション付きのメソッドを見つけ、それらを型コンバーターメカニズムに統合します。例36.3「アノテーションが付けられたコンバータークラスの例」 は、java.io.File
から java.io.InputStream
へ変換するためのコンバーターメソッドと、byte[]
から String
へ変換するための別のコンバーターメソッド (引数 Exchange
を含む) を定義するアノテーション付きコンバータークラスの例を示しています。
例36.3 アノテーションが付けられたコンバータークラスの例
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); } }
toInputStream()
メソッドは File
型から InputStream
型への変換を実行し、toString()
メソッドは byte[]
型から String
型への変換を実行します。
メソッド名は重要ではなく、自由に定義できます。重要なのは、引数の型、戻り値の型、および @Converter
アノテーションです。
TypeConverter ファイルの作成
カスタムコンバーターの検出メカニズム ( アノテーション型コンバーターローダー で実装されている) を有効にするには、以下の場所に TypeConverter
ファイルを作成します。
META-INF/services/org/apache/camel/TypeConverter
この TypeConverter
ファイルには、型コンバータークラスの FQN (完全修飾名) がコンマ区切りで列挙されたリストが含まれている必要があります。たとえば、型コンバーターローダーが YourPackageName.
YourClassName パッケージからアノテーション付きコンバータークラスを検索する場合は、TypeConverter
ファイルの内容は以下のようになります。
com.PackageName.FooClass
検索メカニズムを有効にする別の方法は、TypeConverter
ファイルにパッケージ名のみを追加することです。たとえば、TypeConverter
ファイルの内容は以下のようになります。
com.PackageName
これにより、パッケージスキャナーが @Converter
タグのパッケージをスキャンします。FQN メソッドの使用は高速であり、推奨される方法です。
型コンバーターのパッケージ化
型コンバーターは、カスタム型コンバーターのコンパイルされたクラスと META-INF
ディレクトリーを含む JAR ファイルとしてパッケージ化されます。この JAR ファイルをクラスパスに置き、Apache Camel アプリケーションで利用できるようにします。
フォールバックコンバーターメソッド
@Converter
アノテーションを使用して通常のコンバーターメソッドを定義する他に、@FallbackConverter
アノテーションを使用してフォールバックコンバーターメソッドを定義することもできます。フォールバックコンバーターメソッドは、Master 型コンバーターが型レジストリーで通常のコンバーターメソッドの検索に失敗した場合にのみ試行されます。
通常のコンバーターメソッドとフォールバックコンバーターメソッドの基本的な違いは、通常のコンバーターメソッドが特定の型 (例: byte[]
から String
など) のペア間で変換を実行するのに対し、フォールバックコンバーターは、潜在的に任意 の型のペア間で変換できるところです。どの変換を実行できるかは、フォールバックコンバーターメソッド本体の実装ロジック次第です。実行時に通常のコンバーターで変換できない場合、Master 型コンバーターは変換できるコンバーターを見つけるまで、利用可能なすべてのフォールバックコンバーターを繰り返し実行します。
フォールバックコンバーターのメソッドの署名には、以下のいずれかの形式を使用できます。
// 1. Non-generic form of signature @FallbackConverter public static Object MethodName( Class type, Exchange exchange, Object value, TypeConverterRegistry registry ) // 2. Templating form of signature @FallbackConverter public static <T> T MethodName( Class<T> type, Exchange exchange, Object value, TypeConverterRegistry registry )
MethodName はフォールバックコンバーターの任意のメソッド名です。
たとえば、以下の抜粋コード (File コンポーネントの実装から取得) は、GenericFile
オブジェクトのボディーを変換できるフォールバックコンバーターを示し、型コンバーターレジストリーですでに利用可能な型コンバーターを利用しています。
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; } ... }