JavaBeanをMapに変換するユーティリティ
JavaBeanをMapに変換したり復元したりするユーティリティを書きました。探せばいっぱいありそうなのであれだけど。
使い方
適当なJavaBeanがあるとして、
// テスト用のJavaBean public static class Kitten { private String name; private int age; public Kitten() {} public Kitten( String name, int age ) { this.name = name; this.age = age; } public final String getName () { return name; } public final void setName ( String name ) { this.name = name; } public final int getAge () { return age; } public final void setAge ( int age ) { this.age = age; } @Override public String toString() { return new StringBuilder( name ).append( ":" ).append( age ).toString(); } }
こんな感じで使えます。
Kitten mii = new Kitten("mii", 2); System.out.println( mii.toString() ); // mii:2 // Mapに変換 Map<Property<Kitten,?>,Object> map = Properties.toMap( mii ); for ( Map.Entry<Property<Kitten,?>,Object> e : map.entrySet() ) { System.out.println( e.getKey().getName() + ":" + e.getValue() ); } // 復元 Kitten mii2 = Properties.fromMap( map ); System.out.println( mii2.toString() ); // mii:2 // 値を取得 System.out.println( "\n---get" ); Property<Kitten, String> name = new Property<Kitten,String>( "name", Kitten.class, String.class ); System.out.println( map.get( name ) ); // mii System.out.println( name.get( mii ) ); // mii // 値を設定 System.out.println( "\n---set" ); // プロパティ経由でモデルの値を更新 name.set( mii, "tora" ); System.out.println( mii.toString() ); // tora:2 // mapの値をいじる。 map.put( name, "kuro" ); mii2 = Properties.fromMap( map ); System.out.println( mii2.toString() ); // kuro:2
実行結果です。
mii:2 age:2 name:mii mii:2 ---get mii mii ---set tora:2 kuro:2
実装
以下の通り。
Properties.java
import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; /** * JavaBeanをMapに変換するユーティリティ * * @version $Revision:$ * @author $Author:$ */ public class Properties { /** * モデルを解析して、プロパティと値の{@link Map}に変換します。 * @param <M> モデルの型 * @param model モデル * @return プロパティと値の{@link Map} * * @throws IntrospectionException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException * @throws SecurityException * @throws IllegalArgumentException */ public static final <M> Map<Property<M,?>, Object> toMap( M model ) throws IntrospectionException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { Map<Property<M,?>, Object> map = new HashMap<Property<M,?>, Object>(); BeanInfo info = Introspector.getBeanInfo( model.getClass() ); PropertyDescriptor[] pds = info.getPropertyDescriptors(); for ( PropertyDescriptor pd : pds ) { if ( "class".equals( pd.getName() ) ) { continue; // getClassは無視。 } if ( pd.getWriteMethod() == null ) { throw new IllegalArgumentException( "setter is not exist. property=" + pd.getName()); } if ( pd.getReadMethod() == null ) { throw new IllegalArgumentException( "getter is not exist. property=" + pd.getName()); } Property<M, Object> p = new Property<M, Object>( pd.getName(), (Class<M>)model.getClass(), (Class<Object>) pd.getPropertyType() ); map.put( p, p.get( model ) ); } return map; } /** * プロパティと値の{@link Map}からモデルを復元します。 * * @param <M> モデルの型 * @param map プロパティと値の{@link Map} * @return モデル * * @throws IllegalAccessException * @throws InstantiationException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws IllegalArgumentException * @throws SecurityException */ public static final <M> M fromMap( Map<Property<M,?>, Object> map ) throws InstantiationException, IllegalAccessException, SecurityException, IllegalArgumentException, NoSuchMethodException, InvocationTargetException { if ( map.isEmpty() ) { throw new IllegalArgumentException("empty map."); } Property<M, ?> p = map.keySet().iterator().next(); M model = p.getModelType().newInstance(); for ( Entry<Property<M, ?>, Object> e : map.entrySet() ) { ( (Property<M,Object>) e.getKey() ).set( model, e.getValue() ); } return model; } }
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * プロパティ * * @param <M> モデルの型 * @param <V> 値の型 * * @version $Revision:$ * @author $Author:$ */ public class Property<M, V> { private final Class<M> modelType; private final Class<V> valueType; private final String name; /** * コンストラクタ * @param name プロパティ名 * @param modelType モデルの型 * @param valueType 値の型 */ public Property( String name, Class<M> modelType, Class<V> valueType ) { this.name = name; this.modelType = modelType; this.valueType = valueType; } /** * プロパティ名を取得する * @return プロパティ名 */ public String getName() { return this.name; } /** * モデルの型を取得する * @return モデルの型 */ public Class<M> getModelType() { return this.modelType; } /** * 値の型を取得する * @return 値の型 */ public Class<V> getValueType() { return this.valueType; } /** * プロパティ値を取得する。 * @param model モデル * @return プロパティ値 * * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws NoSuchMethodException * @throws SecurityException */ public final V get( M model ) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException { Method read = model.getClass().getMethod( "get" + toMethodName(getName()) ); return (V) read.invoke( model ); } /** * プロパティ値を設定する。 * @param model モデル * @param value プロパティ値 * * @throws NoSuchMethodException * @throws SecurityException * @throws InvocationTargetException * @throws IllegalAccessException * @throws IllegalArgumentException */ public final void set( M model, V value ) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException { Method write = model.getClass().getMethod( "set" + toMethodName(getName()), getValueType() ); write.invoke( model, value ); } private static final String toMethodName( String name ) { StringBuilder sb = new StringBuilder(); sb.append( name.substring( 0, 1 ).toUpperCase() ); sb.append( name.substring( 1 ) ); return sb.toString(); } /* 継承元のクラスのJavaDocを参照 */ public boolean equals ( Object obj ) { if ( obj == null ) { return false; } if ( obj instanceof Property<?, ?> ) { Object[] that = getValues((Property<?, ?>) obj); return CompareUtil.equalsSeq(that, getValues(this)); } return false; } /* 継承元のクラスのJavaDocを参照 */ public int hashCode () { return CompareUtil.hashCodeSeq(getValues(this)); } private static Object[] getValues(Property<?, ?> v) { return new Object[] { v.getName(), v.getValueType(), v.getModelType() }; } }