de.team33.patterns.collection.ceres.Mapping Maven / Gradle / Ivy
Show all versions of collection-ceres Show documentation
package de.team33.patterns.collection.ceres;
import de.team33.patterns.building.elara.LateBuilder;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
/**
* Some convenience methods to deal with {@link Map}s.
*/
@SuppressWarnings({"ProhibitedExceptionCaught", "unused"})
public final class Mapping {
private Mapping() {
}
/**
* Just like {@link Map#put(Object, Object) subject.put(key, value)} for a given subject,
* but returns the subject.
*
* @throws UnsupportedOperationException if {@link Map#put(Object, Object)} is not supported by the
* subject.
* @throws NullPointerException if subject is {@code null} or ...
* @throws NullPointerException if the specified key or value is {@code null}
* and the subject does not permit {@code null}
* keys or values
* @throws ClassCastException if the class of the specified key or value prevents it
* from being put into the subject
* (may occur only if used raw or forced in a mismatched class context).
* @throws IllegalArgumentException if some property of the specified key or value prevents
* it from being stored in the subject.
* @see Map#put(Object, Object)
*/
public static > M put(final M subject, final K key, final V value) {
subject.put(key, value);
return subject;
}
/**
* Just like {@link Map#putAll(Map) subject.putAll(origin)} for a given subject,
* but returns the subject.
*
* @throws UnsupportedOperationException if {@link Map#putAll(Map)} is not supported by the subject.
* @throws NullPointerException if subject or origin is {@code null} or ...
* @throws NullPointerException if any of the specified keys or values are
* {@code null} and the {@code subject} does not permit {@code null}
* keys or values.
* @throws ClassCastException if the class of any specified key or value prevents it
* from being put into the subject
* (may occur only if used raw or forced in a mismatched class context).
* @throws IllegalArgumentException if some property of any key or value in the specified
* origin prevents it from being stored in the subject.
* @see Map#putAll(Map)
*/
public static > M putAll(final M subject,
final Map extends K, ? extends V> origin) {
subject.putAll(origin);
return subject;
}
/**
* Just like {@link Map#clear() subject.clear()} for a given subject
* but returns the subject.
*
* @throws UnsupportedOperationException if {@link Collection#clear()} is not supported by the subject.
* @throws NullPointerException if subject is {@code null}.
* @see Map#clear()
*/
public static > M clear(final M subject) {
subject.clear();
return subject;
}
/**
* Just like {@link Map#remove(Object) subject.remove(key)} for a given subject
* but returns the subject.
*
* Avoids an unnecessary {@link ClassCastException} or {@link NullPointerException} which might be caused by
* {@link Map#remove(Object)} when the subject does not support the requested key.
*
* @throws UnsupportedOperationException if {@link Map#remove(Object)} is not supported by the subject.
* @throws NullPointerException if subject is {@code null}.
*/
public static > M remove(final M subject, final Object key) {
try {
subject.remove(key);
} catch (final NullPointerException | ClassCastException caught) {
if (null == subject) {
throw caught; // expected to be a NullPointerException
}
// --> can not contain
// --> simply does not contain
// --> Nothing else to do.
}
return subject;
}
/**
* Just like {@link Map#containsKey(Object)} for a given subject.
*
* Avoids an unnecessary {@link ClassCastException} or {@link NullPointerException} which might be caused by
* {@link Map#containsKey(Object)} when the subject does not support the requested key.
*
* @throws NullPointerException if subject is {@code null}.
*/
public static boolean containsKey(final Map, ?> subject, final Object key) {
try {
return subject.containsKey(key);
} catch (final NullPointerException | ClassCastException caught) {
if (null == subject) {
throw caught; // expected to be a NullPointerException
} else {
// --> can not contain
// --> simply does not contain ...
return false;
}
}
}
/**
* Just like {@link Map#containsValue(Object)} for a given subject.
*
* Avoids an unnecessary {@link ClassCastException} or {@link NullPointerException} which might be caused by
* {@link Map#containsValue(Object)} when the subject does not support the requested value.
*
* @throws NullPointerException if subject is {@code null}.
*/
public static boolean containsValue(final Map, ?> subject, final Object value) {
try {
return subject.containsValue(value);
} catch (final NullPointerException | ClassCastException caught) {
if (null == subject) {
throw caught; // expected to be a NullPointerException
} else {
// --> can not contain
// --> simply does not contain ...
return false;
}
}
}
/**
* Just like {@link Map#get(Object)} for a given subject.
*
* Avoids an unnecessary {@link ClassCastException} or {@link NullPointerException} which might be caused by
* {@link Map#get(Object)} when the subject does not support the requested key.
*
* @return The value or {@code null} if the subject doesn't contain (an entry for) the key.
* @throws NullPointerException if subject is {@code null}.
*/
public static V get(final Map, V> subject, final Object key) {
try {
return subject.get(key);
} catch (final NullPointerException | ClassCastException caught) {
if (null == subject) {
throw caught; // expected to be a NullPointerException
} else {
// --> can not contain
// --> simply does not contain
// --> as specified for Map ...
// noinspection ReturnOfNull
return null;
}
}
}
/**
* Supplies a proxy for a given {@link Map subject} that may be used to implement some {@link Map}-specific
* methods, e.g.:
*
* - {@link Object#toString()}
* - {@link Map#equals(Object)}
* - {@link Map#hashCode()}
* - ...
*
*
* @param subject A {@link Map}, that at least provides independently ...
*
* - {@link Map#entrySet()}
*
*/
@SuppressWarnings("AnonymousInnerClass")
public static Map proxy(final Map subject) {
//noinspection ReturnOfInnerClass
return new AbstractMap() {
@Override
public Set> entrySet() {
return subject.entrySet();
}
};
}
/**
* Returns a new {@link Builder} for target instances as supplied by the given {@link Supplier}.
*
* @param The key type of the target instance.
* @param The value type of the target instance.
* @param The final type of the target instance, at least {@link Map}.
*/
public static > Builder builder(final Supplier newTarget) {
return new Builder<>(newTarget, Builder.class);
}
/**
* Returns a new {@link Charger} for a given target instance.
*
* @param The key type of the target instance.
* @param The value type of the target instance.
* @param The final type of the target instance, at least {@link Map}.
*/
public static > Charger charger(final M target) {
return new Charger<>(target, Charger.class);
}
/**
* Utility interface to set up a target instance of {@link Map}.
*
* @param The key type of the target instance.
* @param The value type of the target instance.
* @param The final type of the target instance, at least {@link Map}.
* @param The final type of the Setup implementation.
*/
@SuppressWarnings("ClassNameSameAsAncestorName")
@FunctionalInterface
public interface Setup, S extends Setup>
extends de.team33.patterns.building.elara.Setup {
/**
* Puts a pair of key / value to the instance to be set up.
*
* @throws UnsupportedOperationException if {@link Map#put(Object, Object)} is not supported by the instance
* to be set up.
* @throws NullPointerException if the specified key or value is {@code null}
* and the instance to be set up does not permit {@code null}
* keys or values
* @throws ClassCastException if the class of the specified key or value prevents
* it from being put into the instance to be set up
* (may occur only if used raw or forced in a mismatched class context).
* @throws IllegalArgumentException if some property of the specified key or value
* prevents it from being stored in the instance to be set up.
* @see Map#put(Object, Object)
* @see Mapping#put(Map, Object, Object)
*/
default S put(final K key, final V value) {
return setup(target -> Mapping.put(target, key, value));
}
/**
* Removes a pair of a given key and its associated value from the instance to be set up.
*
* Avoids an unnecessary {@link ClassCastException} or {@link NullPointerException} which might be caused by
* {@link Map#remove(Object)} when the instance to be set up does not support the requested key.
*
* @throws UnsupportedOperationException if {@link Map#remove(Object)} is not supported by the
* subject.
* @see Map#remove(Object)
* @see Mapping#remove(Map, Object)
*/
default S remove(final Object key) {
return setup(target -> Mapping.remove(target, key));
}
/**
* Puts multiple pairs of key / value to the instance to be set up.
*
* If origin is {@code null} it will be treated as an empty {@link Map}.
*
* @throws UnsupportedOperationException if {@link Map#putAll(Map)} is not supported
* by the instance to be set up.
* @throws NullPointerException if any of the specified keys or values are
* {@code null} and the instance to be set up does not permit
* {@code null} keys or values.
* @throws ClassCastException if the class of any specified key or value prevents it
* from being put into the subject
* (may occur only if used raw or forced in a mismatched class context).
* @throws IllegalArgumentException if some property of any key or value in the specified
* origin prevents it from being stored in the subject.
* @see Map#putAll(Map)
* @see Mapping#putAll(Map, Map)
*/
default S putAll(final Map extends K, ? extends V> origin) {
return setup(target -> Mapping.putAll(target, (null == origin) ? Collections.emptyMap() : origin));
}
/**
* Removes all pairs of key / value from the instance to be set up.
*
* @throws UnsupportedOperationException if {@link Collection#clear()} is not supported by the subject.
* @see Map#clear()
* @see Mapping#clear(Map)
*/
default S clear() {
return setup(Mapping::clear);
}
}
/**
* Builder implementation to build target instances of {@link Map}.
*
* Use {@link #builder(Supplier)} to get an instance.
*
* @param The key type of the target instance.
* @param The value type of the target instance.
* @param The final type of the target instance, at least {@link Map}.
*/
public static class Builder>
extends LateBuilder>
implements Setup> {
@SuppressWarnings({"rawtypes", "unchecked"})
private Builder(final Supplier newResult, final Class builderClass) {
super(newResult, builderClass);
}
}
/**
* Charger implementation to charge target instances of {@link Map}.
*
* Use {@link #charger(Map)} to get an instance.
*
* @param The key type of the target instance.
* @param The value type of the target instance.
* @param The final type of the target instance, at least {@link Map}.
*/
@SuppressWarnings("ClassNameSameAsAncestorName")
public static class Charger>
extends de.team33.patterns.building.elara.Charger>
implements Setup> {
@SuppressWarnings({"rawtypes", "unchecked"})
private Charger(final M target, final Class builderClass) {
super(target, builderClass);
}
}
}