36.3. 주석을 사용하여 유형 구현

36.3.1. 개요

유형 변환 메커니즘은 새 슬레이브 유형 변환기를 추가하여 쉽게 사용자 지정할 수 있습니다. 이 섹션에서는 슬레이브 유형 변환기를 구현하고 Apache Camel과 통합하는 방법을 설명하므로 주석 유형 변환기 로더에 의해 자동으로 로드됩니다.

36.3.2. 형식 변환기를 구현하는 방법

사용자 지정 형식 변환기를 구현하려면 다음 단계를 수행합니다.

36.3.3. 주석이 달린 컨버터 클래스 구현

@Converter 주석을 사용하여 사용자 정의 유형 변환기 클래스를 구현할 수 있습니다. 클래스 자체와 형식 변환을 수행하기 위해 각 정적 메서드에 주석을 달아야 합니다. 각 변환기 메서드는 형식에서 정의 하는 인수를 사용 하며 선택적으로 두 번째 Exchange 인수를 사용 하며 입력할 수 있는 값을 정의 하는 비void 반환 값이 있습니다. 유형 변환기 로더는 Java 리플렉션을 사용하여 주석이 달린 방법을 찾아 형식 변환기 메커니즘에 통합합니다. 예 36.3. “Annotated Cryostat 클래스의 예” java.io.File 에서 java.io.InputStream 으로 변환하기 위한 변환기 메서드 및 byte[] 에서 String 으로 변환하는 다른 컨버터 메서드( Exchange 인수 포함)를 정의하는 주석이 있는 변환기 클래스의 예를 보여줍니다.

예 36.3. Annotated Cryostat 클래스의 예

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 주석의 존재 여부입니다.

36.3.4. TypeConverter 파일 만들기

사용자 정의 변환기에 대해 주석 유형 변환기로 구현되는 검색 메커니즘을 활성화하려면 다음 위치에서 TypeConverter 파일을 생성합니다.

META-INF/services/org/apache/camel/TypeConverter

TypeConverter 파일에는 FQN(Fully Qualified Names) 형식 변환기 클래스의 쉼표로 구분된 목록이 포함되어야 합니다. 예를 들어 형식 변환기 로더가 YourPackageName.YourClassName 패키지에 주석이 달린 컨버터 클래스를 검색하도록 하려면 TypeConverter 파일에 다음과 같은 내용이 있습니다.

com.PackageName.FooClass

검색 메커니즘을 활성화하는 다른 방법은 패키지 이름만 TypeConverter 파일에 추가하는 것입니다. 예를 들어 TypeConverter 파일에는 다음과 같은 내용이 있습니다.

com.PackageName

이로 인해 패키지 스캐너가 @Converter 태그의 패키지를 통해 스캔됩니다. FQN 방법을 사용하는 것이 더 빠르고 선호되는 방법입니다.

36.3.5. 유형 변환기 패키지

유형 변환기는 사용자 정의 유형 변환기의 컴파일된 클래스와 META-INF 디렉터리가 포함된 JAR 파일로 패키징됩니다. 이 JAR 파일을 classpath에 배치하여 Apache Camel 애플리케이션에서 사용할 수 있도록 합니다.

36.3.6. 대체 변환기 방법

@Converter 주석을 사용하여 정규식을 정의하는 것 외에도 @FallbackConverter 주석을 사용하여 대체 변환기 메서드를 선택적으로 정의할 수 있습니다. 마스터 유형 변환기가 유형 레지스트리에서 일반 컨버터 메서드를 찾지 못하는 경우에만 대체 변환기 방법이 시도됩니다.

일반 변환기 메서드와 대체 변환기 메서드의 근본적인 차이점은 일반 변환기가 특정 유형 쌍(예: 바이트[] 에서 문자열까지) 간의 변환을 수행하도록 정의되지만 대체 변환기는 모든 유형의 쌍 간에 변환을 수행할 수 있다는 것입니다. 대체 변환기 메서드의 본문에 있는 코드는 수행할 수 있는 변환을 파악합니다. 런타임에 일반 변환기에서 변환을 수행할 수 없는 경우 master 유형 변환기는 변환을 수행할 수 있는 옵션을 찾을 때까지 사용 가능한 모든 대체 변환기를 반복합니다.At run time, if a conversion cannot be performed by a regular converter, the master type converters through every available fallback converter until it finds one that can perform the conversion.

대체 변환기의 메서드 서명에는 다음 양식 중 하나가 있을 수 있습니다.

// 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;
    }
    ...
}