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

com.yahoo.bard.webservice.util.DelegatingMap Maven / Gradle / Ivy

Go to download

Fili web service library provides core capabilities for RESTful aggregation navigation, query planning and metadata

There is a newer version: 1.1.13
Show newest version
// Copyright 2016 Yahoo Inc.
// Licensed under the terms of the Apache license. Please see LICENSE.md file distributed with this work for terms.
package com.yahoo.bard.webservice.util;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.validation.constraints.NotNull;

/**
 * A delegating map has a local copy (self) of keys and values and a next map to which it delegates lookups for values
 * which it doesn't contain. Operations which remove keys from a map throw exceptions because the local map cannot alter
 * its delegate (removing a key with remove(K k) from the map and then still having get(K k) return the value from the
 * delegate would be very surprising behavior on a Map).
 * 

* In order to support predictable iteration ordering, this extends LinkedHashMap with a modified definition of * canonical ordering based on the canonical ordering of non-shadowed keys in the delegate followed by local keys in * insertion order (e.g. LinkedHashMap). * * @param The key type for the map * @param The value type for the map */ public class DelegatingMap extends LinkedHashMap { private final Map delegate; /** * Constructor. *

* Uses a LinkedHashMap as it's base map. */ public DelegatingMap() { this(new LinkedHashMap<>()); } /** * Constructor. * * @param nextMap Map to delegate to */ public DelegatingMap(@NotNull Map nextMap) { this.delegate = nextMap; } @Override public V get(Object key) { return super.containsKey(key) ? super.get(key) : delegate.get(key); } /** * Removes are not allowed: Delegating Map should be changed in a put-only fashion. */ @Override public void clear() { throw new UnsupportedOperationException( "Clear is not defined on DelegatingMap. Add is the only allowed modification operation." ); } /** * Clear the local map. This won't affect the delegate map. */ public void clearLocal() { super.clear(); } @Override public boolean containsKey(Object key) { return super.containsKey(key) || delegate.containsKey(key); } @Override public boolean containsValue(Object o) { return entryStream().map(Map.Entry::getValue).anyMatch(v -> Objects.equals(v, o)); } @Override public Set keySet() { return entryStream() .map(Map.Entry::getKey) .collect(Collectors.toCollection(LinkedHashSet::new)); } /** * Get a stream of map entries. * * @return A stream of entries which are visible from via delegate and those in the local map */ private Stream> entryStream() { return Stream.concat( delegate.entrySet().stream().filter(e -> !super.containsKey(e.getKey())), super.entrySet().stream() ); } @Override public Set> entrySet() { return entryStream().collect(Collectors.toCollection(LinkedHashSet::new)); } /** * Adds the key and value to the local map, potentially overshadowing a version in the delegate map. * * @param key The key to the value * @param value The value being stored * * @return the prior value from the local map (if any) or the shadowed value from the delegate (if any) */ @Override public V put(K key, V value) { V oldValue = super.put(key, value); return (oldValue == null) ? delegate.get(key) : oldValue; } /** * Delegating map should be changed in a put-only fashion. Removes are not allowed. * * @param o Object to be removed * * @return nothing, this is not supported and throws an exception instead */ @Override public V remove(Object o) { throw new UnsupportedOperationException( "Remove is not defined on DelegatingMap. Add is the only allowed modification operation." ); } /** * Remove from the local map. * * @param key key whose mapping is to be removed from the map * * @return the previous value associated with key, or null if there was no mapping for key. */ public V removeLocal(K key) { return super.remove(key); } @Override public int size() { return entrySet().size(); } @Override public Collection values() { return entryStream().map(Map.Entry::getValue).collect(Collectors.toSet()); } /** * Return a non delegating map which snapshots the data visible in this delegating map, disconnected from changes * to this and the underlying delegates. * * @return A non delegating plain-map copy of the data visible in this map */ public LinkedHashMap flatView() { return entryStream() .collect(StreamUtils.toLinkedMap(Map.Entry::getKey, Map.Entry::getValue)); } @Override public int hashCode() { return Objects.hash(super.hashCode(), delegate); } /** * Are these two delegating maps the same in terms of the current layer and their delegates are equal under the * definition of equality for that delegate. * * @param o The object being compared * * @return true if the object being compared has the same local values and their delegates are equal */ @Override public boolean equals(final Object o) { if (! (o instanceof DelegatingMap)) { return false; } DelegatingMap that = (DelegatingMap) o; return super.equals(that) && delegate.equals(that.delegate); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy