Java における Map と JavaBean の動的変換実装

背景と目的

システム開発において、データベースや外部 API から取得したフラットなデータをオブジェクト指向モデルへマッピングする必要があるケースが多くあります。特に、対象クラスのフィールド構成が固定されておらず、キー名に対応する値のみが既知の場合、リフレクション機能を用いた汎用変換ロジックが有効となります。

JavaBean から Map への変換

以下の関数は、指定された Bean インスタンスのプロパティ情報を解析し、その状態を Key-Value ペアを持つ辞書形式(Map)に変換します。Introspector API を使用してクラスのプロパティを取得し、Getter メソッドを通じて値を読み出します。

/**
 * オブジェクトから Map コレクションへの変換を実行します。
 * 
 * @param targetBean 変換対象の JavaBean インスタンス
 * @return プロパティを含む結果の Map 对象
 */
@SuppressWarnings("unchecked")
public static <T> Map<String, Object> beanToMap(final T targetBean) {
    final Map<String, Object> resultMap = new HashMap<>();
    try {
        // クラス情報の取得と解析
        final BeanInfo beanInfo = Introspector.getBeanInfo(targetBean.getClass());
        
        // 各プロパティ記述子のループ処理
        for (final PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
            final String name = descriptor.getName();
            
            // 「class」など不要な内部属性はスキップ
            if (!name.equals("class") && descriptor.getReadMethod() != null) {
                final Method readMethod = descriptor.getReadMethod();
                
                // セッターの呼び出しによる値の取得
                final Object value = readMethod.invoke(targetBean);
                
                // null 値の場合は空文字列として扱うか、そのまま格納するか方針を決める
                // ここではnull以外のみ、あるいはnullでもキーを設定する
                resultMap.put(name, value != null ? value : "");
            }
        }
    } catch (final Exception e) {
        throw new RuntimeException("Bean 変換エラー:" + e.getMessage(), e);
    }
    
    return resultMap;
}

Map から JavaBean への変換

逆に、既存の Map データをベースに新しい Bean インスタンスを構築する場合は、Setter メソッドを介してフィールドに代入する必要があります。ここでは動的生成されたコンストラクタとインスペクタ情報を利用します。

/**
 * Map コレクションのデータを用いて、指定型の JavaBean を構築します。
 * 
 * @param inputData 属性値が含まれる Map
 * @param beanClass 生成したいクラス型情報
 * @return 初期化された JavaBean インスタンス
 */
@SuppressWarnings("unchecked")
public static <T> T mapToBean(
        final Map<String, Object> inputData, 
        final Class<T> beanClass) {
    
    try {
        // クラス情報の解析
        final BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
        
        // 新しいインスタンスの生成(非推奨な newInstance は回避)
        final T instance = beanClass.getDeclaredConstructor().newInstance();
        
        // フィールドへのバインド処理
        for (final PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) {
            final String propertyName = descriptor.getName();
            
            // Map に存在するプロパティのみを対象にする
            if (inputData.containsKey(propertyName)) {
                final Method writeMethod = descriptor.getWriteMethod();
                
                if (writeMethod != null) {
                    final Object value = inputData.get(propertyName);
                    
                    // 引数のセットとメソッド実行
                    writeMethod.invoke(instance, value);
                }
            }
        }
        
        return instance;
        
    } catch (final Exception e) {
        throw new RuntimeException("Map から Bean への変換失敗:" + e.getMessage(), e);
    }
}

タグ: Java リフレクション,Introspector POJO

6月4日 23:14 投稿