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 *      http://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.util.Map;
020
021import org.apache.commons.collections4.KeyValue;
022
023/**
024 * A mutable <code>KeyValue</code> pair that does not implement
025 * {@link java.util.Map.Entry Map.Entry}.
026 * <p>
027 * Note that a <code>DefaultKeyValue</code> instance may not contain
028 * itself as a key or value.
029 *
030 * @since 3.0
031 */
032public class DefaultKeyValue<K, V> extends AbstractKeyValue<K, V> {
033
034    /**
035     * Constructs a new pair with a null key and null value.
036     */
037    public DefaultKeyValue() {
038        super(null, null);
039    }
040
041    /**
042     * Constructs a new pair with the specified key and given value.
043     *
044     * @param key  the key for the entry, may be null
045     * @param value  the value for the entry, may be null
046     */
047    public DefaultKeyValue(final K key, final V value) {
048        super(key, value);
049    }
050
051    /**
052     * Constructs a new pair from the specified <code>KeyValue</code>.
053     *
054     * @param pair  the pair to copy, must not be null
055     * @throws NullPointerException if the entry is null
056     */
057    public DefaultKeyValue(final KeyValue<? extends K, ? extends V> pair) {
058        super(pair.getKey(), pair.getValue());
059    }
060
061    /**
062     * Constructs a new pair from the specified <code>Map.Entry</code>.
063     *
064     * @param entry  the entry to copy, must not be null
065     * @throws NullPointerException if the entry is null
066     */
067    public DefaultKeyValue(final Map.Entry<? extends K, ? extends V> entry) {
068        super(entry.getKey(), entry.getValue());
069    }
070
071    //-----------------------------------------------------------------------
072    /**
073     * Sets the key.
074     *
075     * @param key  the new key
076     * @return the old key
077     * @throws IllegalArgumentException if key is this object
078     */
079    @Override
080    public K setKey(final K key) {
081        if (key == this) {
082            throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a key.");
083        }
084
085        return super.setKey(key);
086    }
087
088    /**
089     * Sets the value.
090     *
091     * @return the old value of the value
092     * @param value the new value
093     * @throws IllegalArgumentException if value is this object
094     */
095    @Override
096    public V setValue(final V value) {
097        if (value == this) {
098            throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a value.");
099        }
100
101        return super.setValue(value);
102    }
103
104    //-----------------------------------------------------------------------
105    /**
106     * Returns a new <code>Map.Entry</code> object with key and value from this pair.
107     *
108     * @return a MapEntry instance
109     */
110    public Map.Entry<K, V> toMapEntry() {
111        return new DefaultMapEntry<>(this);
112    }
113
114    //-----------------------------------------------------------------------
115    /**
116     * Compares this <code>Map.Entry</code> with another <code>Map.Entry</code>.
117     * <p>
118     * Returns true if the compared object is also a <code>DefaultKeyValue</code>,
119     * and its key and value are equal to this object's key and value.
120     *
121     * @param obj  the object to compare to
122     * @return true if equal key and value
123     */
124    @Override
125    public boolean equals(final Object obj) {
126        if (obj == this) {
127            return true;
128        }
129        if (obj instanceof DefaultKeyValue == false) {
130            return false;
131        }
132
133        final DefaultKeyValue<?, ?> other = (DefaultKeyValue<?, ?>) obj;
134        return
135            (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) &&
136            (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
137    }
138
139    /**
140     * Gets a hashCode compatible with the equals method.
141     * <p>
142     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()},
143     * however subclasses may override this.
144     *
145     * @return a suitable hash code
146     */
147    @Override
148    public int hashCode() {
149        return (getKey() == null ? 0 : getKey().hashCode()) ^
150               (getValue() == null ? 0 : getValue().hashCode());
151    }
152
153}