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