0

我在一个项目中使用 BetterBeanBindings,如果我可以对键不是字符串的 Map 进行绑定,那就太好了。

让我们举个例子来说明这种情况:

public class Bean {
    // ...
    private Map<String, AnotherObject> mapOne;
    private Map<SomeObject, AnotherObject> mapTwo;
    // ...

    public Map<String, AnotherObject> getMapOne() {
        return this.mapOne;
    }

    public void setMapOne(Map<String, AnotherObject> mapOne) {
        Map<String, AnotherObject> oldMapOne = this.mapOne;
        this.mapOne = mapOne;
        this.propertyChangeSupport.firePropertyChange("mapOne", oldMapOne, mapOne);
    }

    public Map<SomeObject, AnotherObject> getMapTwo() {
        return this.mapTwo;
    }

    public void setMapTwo(Map<SomeObject, AnotherObject> mapTwo) {
        Map<SomeObject, AnotherObject> oldMapTwo = this.mapTwo;
        this.mapTwo = mapTwo;
        this.propertyChangeSupport.firePropertyChange("mapTwo", oldMapTwo, mapTwo);
    }

    // ...
}

BBB 能够对键为 String 的映射进行绑定(如果我没记错的话,也可以对数字进行绑定,甚至没有原始类型,它们具有标准解析)允许这样做:

Bean bean;
// ...
Bindings.createAutoBinding(UpdateStrategy.READ_WRITE
        bean, BeanProperty.create("mapOne.xxx"),
        whateverBean, whateverProperty);

这将正确地将结果绑定bean.getMapOne().get("xxx")到第 5 个和第 4 个参数中给定对象的给定属性,反之亦然。

但是,如果我们尝试相同的mapTwo

Bindings.createAutoBinding(UpdateStrategy.READ_WRITE
        bean, BeanProperty.create("mapTwo.xxx"),
        whateverOtherOrNotBean, whateverOtherOrNotProperty);

绑定尝试解析bean.getMapTwo().get("xxx"),因为这是属性定义中提供的内容,mapTwo可能不是String, 返回null. 这是有道理的,因为绑定不必知道如何将其String从属性转换为解析所需的对象

有没有办法做到这一点?使用转换器可能有某种解决方法?

4

1 回答 1

0

我做了一个小变通方法,它并不适用于所有情况,但很一般。

事情是使用一个Map<K, V>能够响应类型值K或支持主映射的String值。Map<String, V>

StringBackedMap:

import java.util.Map;
import java.util.Set;

public interface StringBackedMap<K, V> extends Map<K, V> {

    public V get(String key);

    public boolean containsKey(String key);

    public Set<Entry<String, V>> backerEntrySet();

    public Set<String> backerKeySet();

}

StringBackedHashMap:

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class StringBackedHashMap<K, V> extends HashMap<K, V> implements StringBackedMap<K, V> {

    private static final long serialVersionUID = 1L;

    private Map<String, V> backerMap;

    public StringBackedHashMap() {
        super();

        init();
    }

    public StringBackedHashMap(int capacity) {
        super(capacity);

        init();
    }

    public StringBackedHashMap(int capacity, float loadFactor) {
        super(capacity, loadFactor);

        init();
    }

    public StringBackedHashMap(Map<? extends K, ? extends V> map) {
        super(map);

        init();

        putAll(map);
    }

    private void init() {
        this.backerMap = new HashMap<String, V>();
    }

    @Override
    public V get(String key) {
        return this.backerMap.get(key);
    }

    @Override
    public V get(Object key) {
        V value = super.get(key);

        if (value == null) {
            value = this.backerMap.get(key.toString());
        }

        return value;
    }

    @Override
    public boolean containsKey(String key) {
        return this.backerMap.containsKey(key);
    }

    @Override
    public boolean containsKey(Object key) {
        return super.containsKey(key) || this.backerMap.containsKey(key);
    }

    @Override
    public Set<String> backerKeySet() {
        return this.backerMap.keySet();
    }

    @Override
    public Set<Entry<String, V>> backerEntrySet() {
        return this.backerMap.entrySet();
    }

    @Override
    public V put(K key, V value) {
        V oldValue = super.put(key, value);

        this.backerMap.put(key.toString(), value);

        return oldValue;
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> map) {
        super.putAll(map);

        if ((map != null) && (!map.isEmpty())) {
            for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
                this.backerMap.put(entry.getKey().toString(), entry.getValue());
            }
        }
    }

    @Override
    public V remove(Object key) {
        V oldValue = super.remove(key);

        this.backerMap.remove(key.toString());

        return oldValue;
    }

    @Override
    public void clear() {
        super.clear();

        this.backerMap.clear();
    }

}
于 2013-03-15T10:59:19.673 回答