0

我从具有可变映射对象作为字段的库中获取一些 Java 对象。我需要一种方法,通过将地图对象包装在 Collections.unmodifiableMap() 方法中,使这些对象字段在运行时只读。我已经使用 Java Reflection API 尝试了以下方法,但我一直坚持从现场获取实际的地图实例:

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;
}

编辑------------------------------------------------- -------------------------------------------------- -------------------------- 我编写了一个不可变的 Date 类,它将包装一个 java.util.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();
    }

}
}
4

1 回答 1

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;
}
于 2017-11-19T20:00:09.067 回答