org.apache.sshd.common.util.MapEntryUtils Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.sshd.common.util;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
* Represents an un-modifiable pair of values
*
* @author Apache MINA SSHD Project
*/
public final class MapEntryUtils {
@SuppressWarnings({ "rawtypes", "unchecked" })
private static final Comparator> BY_KEY_COMPARATOR = (o1, o2) -> {
Comparable k1 = o1.getKey();
Comparable k2 = o2.getKey();
return k1.compareTo(k2);
};
@SuppressWarnings("rawtypes")
private static final Supplier CASE_INSENSITIVE_MAP_FACTORY = () -> new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
private MapEntryUtils() {
throw new UnsupportedOperationException("No instance");
}
/**
* @param The {@link Comparable} key type
* @param The associated entry value
* @return A {@link Comparator} for {@link java.util.Map.Entry}-ies that compares the key values
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static , V> Comparator> byKeyEntryComparator() {
return (Comparator) BY_KEY_COMPARATOR;
}
public static class GenericMapPopulator> implements Supplier {
private final M map;
public GenericMapPopulator(M map) {
this.map = Objects.requireNonNull(map, "No map provided");
}
public GenericMapPopulator put(K k, V v) {
if (v == null) {
return remove(k);
}
map.put(Objects.requireNonNull(k, "No key provided"), v);
return this;
}
public GenericMapPopulator remove(K k) {
map.remove(k);
return this;
}
public GenericMapPopulator putAll(Map extends K, ? extends V> other) {
if (isNotEmpty(other)) {
other.forEach(this::put);
}
return this;
}
public GenericMapPopulator clear() {
map.clear();
return this;
}
@Override
public M get() {
return map;
}
}
public static class MapBuilder extends GenericMapPopulator> {
public MapBuilder() {
super(new LinkedHashMap<>());
}
@Override
public MapBuilder put(K k, V v) {
super.put(k, v);
return this;
}
@Override
public MapBuilder remove(K k) {
super.remove(k);
return this;
}
@Override
public MapBuilder putAll(Map extends K, ? extends V> other) {
super.putAll(other);
return this;
}
@Override
public MapBuilder clear() {
super.clear();
return this;
}
public Map build() {
return get();
}
public Map immutable() {
return Collections.unmodifiableMap(build());
}
public static MapBuilder builder() {
return new MapBuilder<>();
}
}
public static class NavigableMapBuilder extends GenericMapPopulator> {
public NavigableMapBuilder(Comparator super K> comparator) {
super(new TreeMap<>(Objects.requireNonNull(comparator, "No comparator provided")));
}
@Override
public NavigableMapBuilder put(K k, V v) {
super.put(k, v);
return this;
}
@Override
public NavigableMapBuilder remove(K k) {
super.remove(k);
return this;
}
@Override
public NavigableMapBuilder putAll(Map extends K, ? extends V> other) {
super.putAll(other);
return this;
}
@Override
public NavigableMapBuilder clear() {
super.clear();
return this;
}
public NavigableMap build() {
return get();
}
public NavigableMap immutable() {
return Collections.unmodifiableNavigableMap(build());
}
public static , V> NavigableMapBuilder builder() {
return builder(Comparator.naturalOrder());
}
public static NavigableMapBuilder builder(Comparator super K> comparator) {
return new NavigableMapBuilder<>(comparator);
}
}
public static class EnumMapBuilder, V> extends GenericMapPopulator> {
public EnumMapBuilder(Class keyType) {
super(new EnumMap<>(Objects.requireNonNull(keyType, "No enum class specified")));
}
@Override
public EnumMapBuilder put(K k, V v) {
super.put(k, v);
return this;
}
@Override
public EnumMapBuilder remove(K k) {
super.remove(k);
return this;
}
@Override
public EnumMapBuilder putAll(Map extends K, ? extends V> other) {
super.putAll(other);
return this;
}
@Override
public EnumMapBuilder clear() {
super.clear();
return this;
}
public Map build() {
return get();
}
public Map immutable() {
return Collections.unmodifiableMap(build());
}
public static , V> EnumMapBuilder builder(Class keyType) {
return new EnumMapBuilder<>(keyType);
}
}
public static int size(Map, ?> m) {
return (m == null) ? 0 : m.size();
}
public static boolean isEmpty(Map, ?> m) {
return size(m) <= 0;
}
public static boolean isNotEmpty(Map, ?> m) {
return !isEmpty(m);
}
/**
* @param Type of mapped value
* @return A {@link Supplier} that returns a new {@link NavigableMap} whenever its {@code get()} method
* is invoked
*/
@SuppressWarnings("unchecked")
public static Supplier> caseInsensitiveMap() {
return CASE_INSENSITIVE_MAP_FACTORY;
}
/**
* Flips between keys and values of an input map
*
* @param Original map key type
* @param Original map value type
* @param Flipped map type
* @param map The original map to flip
* @param mapCreator The creator of the target map
* @param allowDuplicates Whether to ignore duplicates on flip
* @return The flipped map result
* @throws IllegalArgumentException if allowDuplicates is {@code false} and a duplicate value found in the
* original map.
*/
public static > M flipMap(
Map extends K, ? extends V> map, Supplier extends M> mapCreator, boolean allowDuplicates) {
M result = Objects.requireNonNull(mapCreator.get(), "No map created");
map.forEach((key, value) -> {
K prev = result.put(value, key);
if ((prev != null) && (!allowDuplicates)) {
ValidateUtils.throwIllegalArgumentException("Multiple values for key=%s: current=%s, previous=%s", value, key,
prev);
}
});
return result;
}
@SafeVarargs
public static > M mapValues(
Function super V, ? extends K> keyMapper, Supplier extends M> mapCreator, V... values) {
return mapValues(keyMapper, mapCreator, GenericUtils.isEmpty(values) ? Collections.emptyList() : Arrays.asList(values));
}
/**
* Creates a map out of a group of values
*
* @param The key type
* @param The value type
* @param The result {@link Map} type
* @param keyMapper The {@link Function} that generates a key for a given value. If the returned key is
* {@code null} then the value is not mapped
* @param mapCreator The {@link Supplier} used to create/retrieve the result map - provided non-empty group of
* values
* @param values The values to be mapped
* @return The resulting {@link Map} - Note: no validation is made to ensure that 2 (or more)
* values are not mapped to the same key
*/
public static > M mapValues(
Function super V, ? extends K> keyMapper,
Supplier extends M> mapCreator,
Collection extends V> values) {
M map = mapCreator.get();
for (V v : values) {
K k = keyMapper.apply(v);
if (k == null) {
continue; // debug breakpoint
}
map.put(k, v);
}
return map;
}
public static NavigableMap toSortedMap(
Iterable extends T> values, Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper, Comparator super K> comparator) {
return GenericUtils.stream(values).collect(toSortedMap(keyMapper, valueMapper, comparator));
}
public static Collector> toSortedMap(
Function super T, ? extends K> keyMapper,
Function super T, ? extends U> valueMapper,
Comparator super K> comparator) {
return Collectors.toMap(keyMapper, valueMapper, throwingMerger(), () -> new TreeMap<>(comparator));
}
public static BinaryOperator throwingMerger() {
return (u, v) -> {
throw new IllegalStateException(String.format("Duplicate key %s", u));
};
}
}