2017-11-19 11 views
1

マップオブジェクトを変更可能なライブラリからいくつかのJavaオブジェクトを取得しています。 Collections.unmodifiableMap()メソッドでマップオブジェクトをラップすることによって、実行時にのみこれらのオブジェクトフィールドを読み取る方法が必要です。私はJavaのリフレクションAPIを使用して、以下のアプローチを試してみましたが、私は、フィールドからの実際のマップのインスタンスを得ることで立ち往生しています:リフレクションを使用して実行時にJava Beanの可変フィールドを変更不能にする方法

public static <T>T freeze(T obj){ 
    if(obj!=null){ 
     Field[] fields=obj.getClass().getDeclaredFields(); 
     for(Field field:fields){ 
      if(field.getType().equals(Map.class)){ 
       //How to wrap a Map instance from the field in Collections.unmodifiableMap() object 
      } 
     } 
    } 
    return obj; 
} 

EDIT --------------- -------------------------------------------------- -------------------------------------------------- ---------- 私はjava.util.Dateオブジェクトをラップし、すべての変更可能な操作を無効にするImmutable Dateクラスを作成しました。このラッパーを使用して、私はCollections.unmodifiableCollection()と同様の機能を得ることができます。

final class DateUtil{ 

private DateUtil(){} 

/** 
* 
* @param date 
* @return Date 
* 
* This method will return an unmodifiable Date object. 
* 
*/ 
public static Date unmodifiableDate(Date date){ 
    if(date==null){ 
     throw new IllegalArgumentException(); 
    } 
    return new ImmutableDate(new Date(date.getTime())); 
} 

/** 
* This Date sub-class will override all the mutable Date operations 
* and throw UnsupportedOperationException. 
*/ 
private final static class ImmutableDate extends Date{ 

    private static final long serialVersionUID = -1869574656923004097L; 
    private final Date date; 

    ImmutableDate(Date date){ 
     this.date=date; 
    } 
    @Override 
    public void setTime(long date) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setDate(int date) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setHours(int hours) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setMinutes(int minutes) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setSeconds(int seconds) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setYear(int year) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public void setMonth(int month) { 
     throw new UnsupportedOperationException(); 
    } 
    @Override 
    public Object clone() { 
     throw new UnsupportedOperationException(); 
    } 

} 
} 

答えて

0

一つの可能​​な解決策は、あなたが、フリーズCollections.unmodifiableMap(に変換)し、その後のオブジェクトに値を設定するオブジェクトからマップ値を取得することです。フィールド操作の前に、field.setAccessible(true)を設定する必要があります。

public static <T>T freeze(T obj) throws IllegalAccessException { 
    if(obj!=null){ 
     Field[] fields=obj.getClass().getDeclaredFields(); 
     for(Field field:fields){ 
      //update accessibility 
      field.setAccessible(true); 
      if(field.getType().equals(Map.class)){ 
       //Convert the map field to Collections.unmodifiableMap() object and update the field 
       field.set(obj, Collections.unmodifiableMap((Map<?, ?>) field.get(obj))); 
      } 
     } 
    } 
    return obj; 
} 
+0

ありがとうございます!このメソッドを呼び出した後にキーを変更/追加しようとすると、java.lang.UnsupportedOperationExceptionがスローされる –

+1

java.util.Dateフィールドでこれを行うことは可能ですか?また、フィールドを最終的に動的にすることもできますか? –

+0

ああ、残念ながら、Javaではjava.util.Dateの不変型はありません。Collections.unmodifiableMapはjava.util.Mapクラス用です(私が知る限り)。 'final'はコンパイル時の言語機能であり、ソースコード内の変数の再割り当てを防ぐので、最終的な修飾子がこの場合に役立つかどうかはわかりません。実行時には(ほとんど)何もしません。しかし、興味深い問題があります:)私は研究を行い、もし私が何かを見つけたら私はあなたと分かち合うでしょう。 – Elka