BeanUtils.copyProperties

今回はSpring Framework の BeanUtils.copyProperties を利用してBeanをコピーしてみました。
BeanUtils.copyPropertiesは、Spring Frameworkが提供するBeanUtilsクラスの一部で、 あるBean(Javaオブジェクト)から別のBeanへプロパティをコピーするためのメソッドです。 両オブジェクト間で同じプロパティ名と型を持っていることが前提ですので注意してください。 (つまりプロパティ名と型が一致するデータのみがコピーされます。)

※この記事は2024/10/23時点の情報です。

BeanUtils.copyPropertiesの制約

型の不一致
プロパティ名が同じでも型が異なる場合、値はコピーされません。 また、BeanUtilsは型変換を行いません。(例えば、Stringをintに変換することはできません)

ネストされたオブジェクト
BeanUtils.copyPropertiesはネストされたオブジェクトのプロパティまでは自動的にコピーしません(深いコピーは行いません)。 ネストされたオブジェクトのプロパティもコピーしたい場合は、カスタムロジックが必要です。

コレクションのコピー
ListやMapなどのコレクション型のフィールドも、オブジェクト自体はコピーされますが、内部の要素まではコピーされません。

com.example.model.TestBean1
コピー元のデータを格納するクラスです。

package com.example.model;

public class TestBean1 {
    private String name;
    private int value;
    private int age;

    public TestBean1() {}
    
    public TestBean1(String name, int value, int age) {
        this.name = name;
        this.value = value;
        this.age = age;
    }

    // ゲッターとセッター
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

com.example.model.TestBean2
コピー先のデータを格納するクラスです。 nameとvalueはTestBean1と同じプロパティ名ですが、testプロパティはTestBean1にはありません。 逆にTestBean1が持っているageプロパティはTestBean2にはありません。

package com.example.model;

public class TestBean2 {
    private String name;
    private int value;
    private String test;

    public TestBean2() {}

    // ゲッターとセッター
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public String getTest() {
        return name;
    }

    public void setTest(String test) {
        this.test = test;
    }

    @Override
    public String toString() {
        return "TestBean2{name='" + name + "', value=" + value + "', test=" + test + '}';
    }
}

com.example.demo.BeanConverter
今回のメインプログラムです。BeanUtilsを使ってプロパティをコピーしています。 単体オブジェクトのコピーと配列でのコピーを行っています。配列の場合は汎用メソッドでコピーしています。

package com.example.demo;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;

import com.example.model.TestBean1;
import com.example.model.TestBean2;

public class BeanConverter {

	public static void main(String[] args) {
		//---------------------------------------------------
		// ★単体でのコピー
		//---------------------------------------------------
		// コピー元のクラス
		TestBean1 fromBean = new TestBean1("example0", 200, 24);
		// コピー先のクラス
		TestBean2 toBean = new TestBean2();
		// BeanUtilsを使ってプロパティをコピー(同じプロパティ名と型のデータのみ)
		BeanUtils.copyProperties(fromBean, toBean);
		// 結果確認
		System.out.println(toBean);

		//---------------------------------------------------
		// ★配列でのコピー
		//---------------------------------------------------
		// サンプルとしてデータを用意
		List<TestBean1> testList1 = new ArrayList<>();
		testList1.add(new TestBean1("example1", 100, 30));
		testList1.add(new TestBean1("example2", 150, 18));
		testList1.add(new TestBean1("example3", 120, 26));
		// TestBean1の配列をTest2Beanの配列にコピー
		List<TestBean2> targetList = copyBeanList(testList1, TestBean2.class);
		// 結果確認
		targetList.forEach(System.out::println);
	}

	// 汎用メソッド: List<T>からList<U>へBeanをコピーする
	public static <T, U> List<U> copyBeanList(List<T> sourceList, Class<U> targetClass) {
		// 戻り値用の配列
		List<U> targetList = new ArrayList<>();
		// コピー元のリストをループ
		for (T sourceObject : sourceList) {
			try {
				// コピー先のクラスのインスタンス
				U targetObject = targetClass.getDeclaredConstructor().newInstance();
				// BeanUtilsを使ってプロパティをコピー(同じプロパティ名と型のデータのみ)
				BeanUtils.copyProperties(sourceObject, targetObject);
				// 戻り値用の配列にセット
				targetList.add(targetObject);
			} catch (Exception e) {
				// エラーハンドリング
				e.printStackTrace();
			}
		}
		// リターン
		return targetList;
	}

}

処理結果は次の通りです。

TestBean2{name='example0', value=200', test=null}
TestBean2{name='example1', value=100', test=null}
TestBean2{name='example2', value=150', test=null}
TestBean2{name='example3', value=120', test=null}

今回はSpring Framework の BeanUtils.copyProperties を利用してBeanをコピーするサンプルプログラムを掲載しましたが、 ご理解頂けたでしょうか?使いこなせれば非常に便利ですが、あくまでプロパティ名と型が両オブジェクトで一致することが前提なので どちらか一方のプロパティ名を変更してしまうとコピーされなくなります。また、全く関係ないオブジェクトであっても プロパティ名と型が一致していたらコピーされてしまうので、意図しないコピーが発生するケースも考えられるので、その辺は注意して下さい。

BeanUtils.copyPropertiesを覚えられましたか?

よく分からなったという人は実際にプログラムを書いて実行してみましょう!

管理人情報