@@ -0,0 +1,2245 @@
+package poussecafe.storable;%0A%0Aimport java.util.Collection;%0Aimport java.util.Collections;%0Aimport java.util.HashMap;%0Aimport java.util.Map;%0Aimport java.util.Optional;%0A%0Aimport static poussecafe.check.Checks.checkThatValue;%0A%0Apublic abstract class MapPropertyCollectionWrapper%3CK, D, E extends D%3E implements MapProperty%3CK, D%3E %7B%0A%0A    public MapPropertyCollectionWrapper(Collection%3CE%3E collection) %7B%0A        checkThatValue(collection).notNull();%0A        this.wrappedCollection = collection;%0A        buildMap();%0A    %7D%0A%0A    private Collection%3CE%3E wrappedCollection;%0A%0A    private void buildMap() %7B%0A        map = new HashMap%3C%3E();%0A        for(D data : wrappedCollection) %7B%0A            map.put(extractKey(data), data);%0A        %7D%0A    %7D%0A%0A    private Map%3CK, D%3E map;%0A%0A    protected abstract K extractKey(D data);%0A%0A    @Override%0A    public Map%3CK, D%3E get() %7B%0A        return Collections.unmodifiableMap(map);%0A    %7D%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    @Override%0A    public void set(Map%3CK, D%3E value) %7B%0A        wrappedCollection.clear();%0A        for(D data : value.values()) %7B%0A            wrappedCollection.add((E) data);%0A        %7D%0A        buildMap();%0A    %7D%0A%0A    @Override%0A    public Optional%3CD%3E get(K key) %7B%0A        if(map.containsKey(key)) %7B%0A            return Optional.of(map.get(key));%0A        %7D else %7B%0A            return Optional.empty();%0A        %7D%0A    %7D%0A%0A    @SuppressWarnings(%22unchecked%22)%0A    @Override%0A    public void put(K key,%0A            D value) %7B%0A        if(map.containsKey(key)) %7B%0A            remove(key);%0A        %7D%0A        K extractedKey = extractKey(value);%0A        if(!extractedKey.equals(key)) %7B%0A            throw new IllegalArgumentException(%22Key does not match value%22);%0A        %7D%0A        map.put(key, value);%0A        wrappedCollection.add((E) value);%0A    %7D%0A%0A    @Override%0A    public Collection%3CD%3E values() %7B%0A        return Collections.unmodifiableCollection(wrappedCollection);%0A    %7D%0A%0A    @Override%0A    public D remove(K key) %7B%0A        if(map.containsKey(key)) %7B%0A            D removedData = map.remove(key);%0A            wrappedCollection.remove(removedData);%0A            return removedData;%0A        %7D else %7B%0A            return null;%0A        %7D%0A    %7D%0A%0A    @Override%0A    public boolean isEmpty() %7B%0A        return wrappedCollection.isEmpty();%0A    %7D%0A%0A%7D%0A

Add MapProperty collection wrapper.