    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      https://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.collections4.keyvalue;
    018
    019import java.io.Serializable;
    020import java.util.Map;
    021import java.util.Map.Entry;
    022import java.util.Objects;
    023
    024import org.apache.commons.collections4.KeyValue;
    025
    026/**
    027 * A {@link Entry Map.Entry} tied to a map underneath.
    028 * <p>
    029 * This can be used to enable a map entry to make changes on the underlying
    030 * map, however this will probably mess up any iterators.
    031 * </p>
    032 *
    033 * @param <K> The type of keys
    034 * @param <V> The type of mapped values
    035 * @since 3.0
    036 */
    037public class TiedMapEntry<K, V> implements Map.Entry<K, V>, KeyValue<K, V>, Serializable {
    038
    039    /** Serialization version */
    040    private static final long serialVersionUID = -8453869361373831205L;
    041
    042    /** The map underlying the entry/iterator */
    043    private final Map<K, V> map;
    044
    045    /** The key */
    046    private final K key;
    047
    048    /**
    049     * Constructs a new entry with the given Map and key.
    050     *
    051     * @param map  The map
    052     * @param key  The key
    053     */
    054    public TiedMapEntry(final Map<K, V> map, final K key) {
    055        this.map = map;
    056        this.key = key;
    057    }
    058
    059    /**
    060     * Compares this {@code Map.Entry} with another {@code Map.Entry}.
    061     * <p>
    062     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
    063     *
    064     * @param obj  The object to compare to
    065     * @return true if equal key and value
    066     */
    067    @Override
    068    public boolean equals(final Object obj) {
    069        if (obj == this) {
    070            return true;
    071        }
    072        if (!(obj instanceof Map.Entry)) {
    073            return false;
    074        }
    075        final Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
    076        return
    077            Objects.equals(key, other.getKey()) &&
    078            Objects.equals(getValue(), other.getValue());
    079    }
    080
    081    /**
    082     * Gets the key of this entry
    083     *
    084     * @return The key
    085     */
    086    @Override
    087    public K getKey() {
    088        return key;
    089    }
    090
    091    /**
    092     * Gets the value of this entry direct from the map.
    093     *
    094     * @return The value
    095     */
    096    @Override
    097    public V getValue() {
    098        return map.get(key);
    099    }
    100
    101    /**
    102     * Gets a hashCode compatible with the equals method.
    103     * <p>
    104     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
    105     *
    106     * @return A suitable hash code
    107     */
    108    @Override
    109    public int hashCode() {
    110        final Object value = getValue();
    111        return (getKey() == null ? 0 : getKey().hashCode()) ^
    112               (value == null ? 0 : value.hashCode());
    113    }
    114
    115    /**
    116     * Sets the value associated with the key direct onto the map.
    117     *
    118     * @param value  The new value
    119     * @return The old value
    120     * @throws IllegalArgumentException if the value is set to this map entry
    121     */
    122    @Override
    123    public V setValue(final V value) {
    124        if (value == this) {
    125            throw new IllegalArgumentException("Cannot set value to this map entry");
    126        }
    127        return map.put(key, value);
    128    }
    129
    130    /**
    131     * Gets a string version of the entry.
    132     *
    133     * @return entry as a string
    134     */
    135    @Override
    136    public String toString() {
    137        return getKey() + "=" + getValue();
    138    }
    139
    140}