36.3. 使用注解实现类型转换程序
概述 复制链接链接已复制到粘贴板!
通过添加新的 worker 类型转换器,可以轻松地自定义类型转换。本节论述了如何实施 worker 类型转换器以及如何将其与 Apache Camel 集成,以便注解类型转换器自动载入。
如何实施类型转换器 复制链接链接已复制到粘贴板!
实施注解的转换器类 复制链接链接已复制到粘贴板!
您可以使用 @Converter 注释实施自定义类型转换器类。您必须注解类本身以及用于执行类型转换的每个 静态方法。每个转换器方法都会使用一个参数来定义 from 类型,该参数可以选择使用第二个 Exchange 参数,并且具有定义 to 类型的非无效返回值。类型转换器使用 Java 反映来查找注释的方法并将其集成到类型转换器机制中。例 36.3 “Annotated Converter 类示例” 显示了一个注释转换器类的示例,它定义了一个转换器方法从 java.io.File 转换为 java.io.InputStream 和另一个转换器方法(带有 Exchange 参数),用于从 byte[] 转换为 String。
例 36.3. Annotated Converter 类示例
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 类型。
方法名称是 unimportant,可以是您选择的任何内容。重要的是参数类型、返回类型和 @Converter 注释。
创建 TypeConverter 文件 复制链接链接已复制到粘贴板!
要启用自定义转换器的发现机制(由 注解类型转换器实现),请在以下位置创建一个 TypeConverter 文件:
META-INF/services/org/apache/camel/TypeConverter
TypeConverter 文件必须包含类型为转换器类的完全限定域名(FQN)的逗号分隔列表。例如,如果您希望类型转换器搜索 YourPackageName.YourClassName 软件包来注解的转换器类,则 TypeConverter 文件将具有以下内容:
com.PackageName.FooClass
启用发现机制的一种替代方法是仅将软件包名称添加到 TypeConverter 文件中。例如,TypeConverter 文件将包含以下内容:
com.PackageName
这将导致软件包扫描程序通过 @Converter 标签的软件包进行扫描。使用 FQN 方法速度更快,它是首选的方法。
打包类型转换器 复制链接链接已复制到粘贴板!
类型转换器被打包为 JAR 文件,其中包含编译的自定义类型转换器和 META-INF 目录。将此 JAR 文件放在 classpath 上,使其可供您的 Apache Camel 应用程序使用。
回退转换器方法 复制链接链接已复制到粘贴板!
除了使用 @Converter 注释定义常规转换器方法外,您还可以选择使用 @FallbackConverter 注释来定义回退转换器方法。只有在控制器类型转换器无法在类型 registry 中找到常规转换器方法时,才会尝试回退转换器方法。
常规转换器方法和回退转换器方法之间的基本区别在于,定义了常规转换器以在特定类型(例如,从 byte[] 到 String)之间执行转换,回退转换器可以在 任意 对类型之间执行转换。它最多是回退转换器方法正文中的代码,以找出它可以执行哪些转换。在运行时,如果转换无法由常规转换器执行,控制器类型转换器会迭代每个可用的回退转换器,直到找到可执行转换的内容。
回退转换器的方法签名可以有以下格式之一:
// 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 对象的正文,利用类型转换器 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;
}
...
}