All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tenidwa.collections.utils.ContentMap Maven / Gradle / Ivy

The newest version!
package org.tenidwa.collections.utils;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * Map that uses function of K as keys instead of K.
 * 

* Its purpose is to allow mapping from keys that don't support * {@link Object#equals(Object)}. When using the usual {@link Map} that has an * interface as a key type, there is no sane way to treat instances of * different types as equal, because then we'd have to: *

    *
  • re-implement {@link Object#equals(Object)} in every type (which would * be a lot of duplicated code);
  • *
  • or extend every implementation of the interface with an abstract * class that implements {@link Object#equals(Object)} using methods of that * interface (which would still be duplicating code, not per interface * implementation but per interface).
  • *
*

* "Content" in "ContentMap" means "something equatable that is obtained with * public methods of interface {@code K}" *

* For example, if {@code PersonWithoutEquals} and {@code PersonFromStream} * don't implement equals but have method {@code Person#name()} that returns * {@link String}, we could map {@code Person}s to something else like this: *

 *     Map map =
 *         new ContentMap(Person::name);
 *     map.put(new PersonWithoutEquals("Jeff"), 1);
 *     map.get(new PersonFromStream(streamWithNameJeff)); // 1
 * 
*

* This map has deterministic ordering. *

* This map doesn't support methods {@link Map#keySet()} and * {@link Map#entrySet()} because it doesn't store the keys of type * {@code K}, it just uses those to obtain the "hidden" keys of type {@code C}. *

* This map is immutable, mutator methods will throw * {@link UnsupportedOperationException}. * @param Key type * @param Some content obtainable from K * @param Value type * @author Georgy Vlasov ([email protected]) * @version $Id$ * @since 0.6.0 */ public final class ContentMap implements Map { /** * Map from content of the base map to its values. */ private final transient ImmutableMap map; /** * Function to extract content from keys. */ private final transient Function function; /** * Original map. */ private final transient Map original; /** * Ctor. * @param base Base map. * @param function Function to get content of a key. */ public ContentMap( final ImmutableMap base, final Function function ) { this.function = function; this.map = this.mapContentToValues(base); this.original = base; } @Override public int size() { return this.map.size(); } @Override public boolean isEmpty() { return this.map.isEmpty(); } @Override public boolean containsKey(Object o) { return this.map.containsKey(this.key(o)); } @Override public boolean containsValue(Object o) { return this.map.containsValue(o); } @Override public V get(Object o) { return this.map.get(this.key(o)); } @Deprecated @Override public V put(K k, V v) { throw new UnsupportedOperationException( "Put operation is not supported" ); } @Deprecated @Override public V remove(Object o) { throw new UnsupportedOperationException( "Remove operation is not supported" ); } @Deprecated @Override public void putAll(Map map) { throw new UnsupportedOperationException( "Put all operation is not supported" ); } @Deprecated @Override public void clear() { throw new UnsupportedOperationException( "Clear operation is not supported" ); } @Override public Set keySet() { return ImmutableSet.copyOf(this.original.keySet()); } @Override public Collection values() { return this.map.values(); } @Override public Set> entrySet() { return ImmutableSet.copyOf(this.original.entrySet()); } @SuppressWarnings("unchecked") private C key(Object o) { return this.function.apply((K)o); } /** * Maps the content of the base map to its values. * @param base Base map * @return Map from content of the base map to its values. */ private ImmutableMap mapContentToValues( final ImmutableMap base ) { final ImmutableMap.Builder builder = ImmutableMap.builder(); for (final Entry entry : base.entrySet()) { builder.put( this.key(entry.getKey()), entry.getValue() ); } return builder.build(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy