Beanのコピー時に自動で型変換する

例えば画面で入力されたフォームの内容を検索条件に変換するといった場合、プロパティ名・型が同じならば以下のように書くことができます。

private MyCondition createCondition(MyCommand command) {
    MyCondition condition = new MyCondition();
    org.springframework.beans.BeanUtils.copyProperties(command, condition);
    return condition;
}

この方法は型が異なる場合だと使えません。そこでSpringのJavaBeansアクセスAPIと型変換サービスを利用して簡単に変換できるようなクラスを作ってみました。

public class BeanConverter {

    @Autowired
    private ConversionService conversionService;

    public <T> T convert(Object source, Class<T> clazz) {

        T target = BeanUtils.instantiate(clazz);

        BeanWrapper sourceWrapper = PropertyAccessorFactory
                .forBeanPropertyAccess(source);
        PropertyDescriptor[] sourceDescs = sourceWrapper
                .getPropertyDescriptors();

        BeanWrapper targetWrapper = PropertyAccessorFactory
                .forBeanPropertyAccess(target);

        String propertyName = null;
        for (PropertyDescriptor sourceDesc : sourceDescs) {
            propertyName = sourceDesc.getName();

            TypeDescriptor typeDesc = targetWrapper
                    .getPropertyTypeDescriptor(propertyName);
            if (null == typeDesc) {
                continue;
            }
            if (!targetWrapper.isWritableProperty(propertyName)) {
                continue;
            }

            Object value = sourceWrapper.getPropertyValue(propertyName);
            if (null == value || "".equals(value)) {
                targetWrapper.setPropertyValue(propertyName, null);
            } else {
                targetWrapper.setPropertyValue(propertyName, conversionService
                        .convert(value, typeDesc.getType()));
            }
        }
        return target;
    }
}

かなりざっくりとした感じでまだ色々とブラッシュアップしなきゃいけない部分は多々ありますが、取り敢えず今のプロジェクトだと問題なさげなのでメモとして残しておきます。使い方はこんな感じ。

private MyCondition createCondition(MyCommand command) {
    BeanConverter converter = new BeanConverter();
    MyCondition condition = converter.convert(command, MyCondition.class);
    return condition;
}

そもそもこんなクラスを使わなくてもSpring Framework、或いは他のOSSに同じようなことをもっと確実に行ってくれるクラスがあると思いますが探せなかったので。