5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

SpringのBeanWrapperで文字列で指定したプロパティに動的アクセスする

Last updated at Posted at 2018-06-20

1. はじめに

今回はSpring FrameworkのBeanWrapperを利用して、文字列で指定したプロパティに動的にアクセスする方法について紹介したいと思います。
BeanWrapperについて簡単に説明すると「Setter,Getterを使わずに、プロパティの値を設定したり取得したりするAPI」です。
プロパティに動的にアクセスするライブラリというと「Apache Commons BeanUtils」を思い浮かべる人もいるかと思いますが、同じような目的の機能です。

1.1. BeanWrapperとは?

Spring Framework(Core)の公式ガイドライン「3.4. Bean manipulation and the BeanWrapper」でもしっかりと紹介されています。
基本的な使い方は以下の通りです。

  • BeanWrapperのインスタンスを生成する
  • setPropertyValueメソッドでプロパティに値を設定する
  • getPropertyValueメソッドでプロパティの値を取得する
  • プロパティは決められたルール(Expression)で指定する

プロパティを指定するルール(Expression)も公式ガイドラインに記載されています。

Table 11. Examples of properties

Expression Explanation
name Indicates the property name corresponding to the methods getName() or isName() and setName(..)
account.name Indicates the nested property name of the property account corresponding e.g. to the methods getAccount().setName() or getAccount().getName()
account[2] Indicates the third element of the indexed property account. Indexed properties can be of type array, list or other naturally ordered collection
account[COMPANYNAME] Indicates the value of the map entry indexed by the key COMPANYNAME of the Map property account

基本的な使い方は説明されていますが、残念なのはコレクション(account[2]account[COMPANYNAME])を操作するサンプルが記載されていないことです。
今回はこのコレクションのサンプルについて説明したいと思います。

2.1. BeanWrapperの使い方

コレクションのプロパティを操作する場合、操作する深さによって使い方が異なります。今回は以下の2つのパターンについて説明したいと思います。

  • コレクションに格納する要素を設定する
  • コレクションに格納されている要素のプロパティに値を設定する
BeanWrapperDemo.java
package demo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

public class BeanWrapperDemo {

	public static void main(String[] args) {
		// コレクションに格納する要素を設定する
		test01();
		// コレクションに格納されている要素のプロパティに値を設定する
		test02();
	}

	// ★ポイント1
	private static void setPropertyValues(Object target, Map<String, Object> input) {
		BeanWrapper wrapper = new BeanWrapperImpl(target);
		for (String key : input.keySet()) {
			wrapper.setPropertyValue(key, input.get(key));
		}
	}
	
	// コレクションに格納する要素を設定する
	private static void test01() {
		try {
			// ★ポイント2
			Team team = new Team();
			List<Member> memberList = new ArrayList<>();
			Map<String, Item> items = new HashMap<>();
			team.setMemberList(memberList);
			team.setItems(items);
			
			Member taro = new Member();
			taro.setMail("test@test.com");
			taro.setName("TARO YAMADA");
			Member hanako = new Member();
			hanako.setMail("hanako@example.com");
			hanako.setName("HANAKO TOYOSU");
			
			Item notepc = new Item();
			notepc.setItemName("ノートPC");
			notepc.setPrice(100000);
			Item book = new Item();
			book.setItemName("Spring徹底入門");
			book.setPrice(4000);
			
			Map<String, Object> input = new HashMap<>();
			input.put("teamId", "01234");
			input.put("teamName", "HelloWorld");
			input.put("point", 100);
			// ★ポイント3
			input.put("memberList[0]", taro);
			input.put("memberList[1]", hanako);
			input.put("items[A01]", notepc);
			input.put("items[A02]", book);
			
			setPropertyValues(team, input);
			System.out.println(team);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	// コレクションに格納されている要素のプロパティに値を設定する
	private static void test02() {
		try {
			// ★ポイント4
			Team team = new Team();
			List<Member> memberList = new ArrayList<>();
			memberList.add(new Member());
			memberList.add(new Member());
			Map<String, Item> items = new HashMap<>();
			items.put("A01", new Item());
			items.put("A02", new Item());

			team.setMemberList(memberList);
			team.setItems(items);
			
			Map<String, Object> input = new HashMap<>();
			input.put("teamId", "01234");
			input.put("teamName", "HelloWorld");
			input.put("point", 100);
			// ★ポイント5
			input.put("memberList[0].mail", "test@test.com");
			input.put("memberList[0].name", "TARO YAMADA");
			input.put("memberList[1].mail", "hanako@example.com");
			input.put("memberList[1].name", "HANAKO TOYOSU");
			input.put("items[A01].itemName", "ノートPC");
			input.put("items[A01].price", 100000);
			input.put("items[A02].itemName", "Spring徹底入門");
			input.put("items[A02].price", 4000);
			
			setPropertyValues(team, input);
			System.out.println(team);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

}

★ポイント1
BeanWrapperのインスタンスを生成します。
org.springframework.beans.BeanWrapperはインターフェースです。
実装クラスはorg.springframework.beans.BeanWrapperImplで、コンストラクタはいくつかありますが、今回はオブジェクトを引数に取るものを利用します。
値を設定するにはsetPropertyValueメソッドを利用します。第1引数はプロパティを指定するルール(Expression)、第2引数は設定したい値です。
詳細についてはJavadocを参照してください。

★ポイント2
「コレクションに格納する要素を設定する」場合、対象となるコレクションがインスタンス化されている必要があります。
コレクションの中身は不要です。

★ポイント3
コレクションに格納する要素を設定するには[]でコレクションの要素の位置を指定します。

  • List(順序付のリスト、配列)の場合、[]に操作対象となるインデックス(0から開始)を指定します。
  • Mapの場合、[]に操作対象となるキーを指定します。

★ポイント4
「コレクションに格納されている要素のプロパティに値を設定する」場合、対象となるコレクションのその要素までインスタンス化されている必要があります。

  • List(順序付のリスト、配列)の場合、操作対象となるインデックスまで要素を追加してください。
  • Mapの場合、操作対象となるキーで要素を追加してください。

★ポイント5
[]でコレクションの位置を指定した後、.プロパティ名で設定対象となるプロパティを指定します。
対象となるコレクションの要素がインスタンス化されていない場合、例外が発生します。
そのため、事前に必ず★ポイント4で操作対象の要素をインスタンス化する必要があります。

2.2. (参考)モデルクラス(POJO)の定義

参考までに、入れ子のコレクションが分かるようにモデルクラスを記載します。

Team.java
package demo;

import java.util.List;
import java.util.Map;

public class Team {
	private String teamId;
	private String teamName;
	private int point;
	private List<Member> memberList;
	private Map<String, Item> items;

	// setter,getter omitted
	// override toString generated by eclipse
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Team [teamId=");
		builder.append(teamId);
		builder.append(", teamName=");
		builder.append(teamName);
		builder.append(", point=");
		builder.append(point);
		builder.append(", memberList=");
		builder.append(memberList);
		builder.append(", items=");
		builder.append(items);
		builder.append("]");
		return builder.toString();
	}
}
Member.java
package demo;

import java.util.Map;

public class Member {
	private String mail;
	private String name;
	private Map<String, String> memo;

	// setter,getter omitted
	// override toString generated by eclipse
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Member [mail=");
		builder.append(mail);
		builder.append(", name=");
		builder.append(name);
		builder.append(", memo=");
		builder.append(memo);
		builder.append("]");
		return builder.toString();
	}
}
Item.java
package demo;

public class Item {
	private String itemName;
	private int price;

	// setter,getter omitted
	// override toString generated by eclipse
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append("Item [itemName=");
		builder.append(itemName);
		builder.append(", price=");
		builder.append(price);
		builder.append("]");
		return builder.toString();
	}
}

3. さいごに

今回はSpring FrameworkのBeanWrapperを利用して文字列で指定したプロパティに動的にアクセスする方法について説明しました。
便利なBeanWrapperですが、処理性能についてはもちろん普通の'Setter,Getter'を利用した方がいいです。
BeanWrapperの使いどころとしては、①動的アクセスが必要となる汎用的な処理や、②文字列でプロパティを指定できる利便性を利用してテストクラスで入力値を設定する等かと思います。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?