org.infinispan.commons.util.Immutables Maven / Gradle / Ivy
package org.infinispan.commons.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Reader;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import org.infinispan.commons.marshall.AbstractExternalizer;
import org.infinispan.commons.marshall.Ids;
import org.infinispan.commons.marshall.MarshallUtil;
/**
* Factory for generating immutable type wrappers.
*
* @author Jason T. Greene
* @author Galder Zamarreño
* @author Tristan Tarrant
* @since 4.0
*/
public class Immutables {
/**
* Whether or not this collection type is immutable
*
* @param o a Collection, Set, List, or Map
* @return true if immutable, false if not
*/
public static boolean isImmutable(Object o) {
return o instanceof Immutable;
}
/**
* Converts a Collection to an immutable List by copying it.
*
* @param source the collection to convert
* @return a copied/converted immutable list
*/
public static List immutableListConvert(Collection extends T> source) {
return new ImmutableListCopy<>(source);
}
/**
*
* Creates an immutable copy of the list.
*
* @param list the list to copy
* @return the immutable copy
*/
public static List immutableListCopy(List list) {
if (list == null) return null;
if (list.isEmpty()) return Collections.emptyList();
if (list.size() == 1) return Collections.singletonList(list.get(0));
return new ImmutableListCopy<>(list);
}
/**
* Creates an immutable copy of the properties.
*
* @param properties the TypedProperties to copy
* @return the immutable copy
*/
public static TypedProperties immutableTypedProperties(TypedProperties properties) {
if (properties == null) return null;
return new ImmutableTypedProperties(properties);
}
/**
* Wraps an array with an immutable list. There is no copying involved.
*
* @param array the array to wrap
* @return a list containing the array
*/
public static List immutableListWrap(T... array) {
return new ImmutableListCopy<>(array);
}
/**
* Creates a new immutable list containing the union (combined entries) of both lists.
*
* @param list1 contains the first elements of the new list
* @param list2 contains the successor elements of the new list
* @return a new immutable merged copy of list1 and list2
*/
public static List immutableListMerge(List extends T> list1, List extends T> list2) {
return new ImmutableListCopy<>(list1, list2);
}
public static ImmutableListCopy immutableListAdd(List list, int position, T element) {
T[] copy = (T[]) new Object[list.size() + 1];
for (int i = 0; i < position; i++) {
copy[i] = list.get(i);
}
copy[position] = element;
for (int i = position; i < list.size(); i++) {
copy[i + 1] = list.get(i);
}
return new ImmutableListCopy<>(copy);
}
public static ImmutableListCopy immutableListReplace(List list, int position, T element) {
T[] copy = (T[]) new Object[list.size()];
for (int i = 0; i < position; i++) {
copy[i] = list.get(i);
}
copy[position] = element;
for (int i = position + 1; i < list.size(); i++) {
copy[i] = list.get(i);
}
return new ImmutableListCopy<>(copy);
}
public static List immutableListRemove(List list, int position) {
T[] copy = (T[]) new Object[list.size() - 1];
for (int i = 0; i < position; i++) {
copy[i] = list.get(i);
}
for (int i = position + 1; i < list.size(); i++) {
copy[i - 1] = list.get(i);
}
return new ImmutableListCopy<>(copy);
}
/**
* Converts a Collections into an immutable Set by copying it.
*
* @param collection the collection to convert/copy
* @return a new immutable set containing the elements in collection
*/
public static Set immutableSetConvert(Collection extends T> collection) {
return immutableSetWrap(new HashSet(collection));
}
/**
* Wraps a set with an immutable set. There is no copying involved.
*
* @param set the set to wrap
* @return an immutable set wrapper that delegates to the original set
*/
public static Set immutableSetWrap(Set extends T> set) {
return new ImmutableSetWrapper<>(set);
}
/**
* Creates an immutable copy of the specified set.
*
* @param set the set to copy from
* @return an immutable set copy
*/
public static Set immutableSetCopy(Set set) {
if (set == null) return null;
if (set.isEmpty()) return Collections.emptySet();
if (set.size() == 1) return Collections.singleton(set.iterator().next());
return new ImmutableSetWrapper<>(new HashSet<>(set));
}
/**
* Wraps a map with an immutable map. There is no copying involved.
*
* @param map the map to wrap
* @return an immutable map wrapper that delegates to the original map
*/
public static Map immutableMapWrap(Map extends K, ? extends V> map) {
return new ImmutableMapWrapper<>(map);
}
/**
* Creates an immutable copy of the specified map.
*
* @param map the map to copy from
* @return an immutable map copy
*/
public static Map immutableMapCopy(Map map) {
if (map == null) return null;
if (map.isEmpty()) return Collections.emptyMap();
if (map.size() == 1) {
Map.Entry me = map.entrySet().iterator().next();
return Collections.singletonMap(me.getKey(), me.getValue());
}
return new ImmutableMapWrapper<>(new HashMap<>(map));
}
/**
* Creates a new immutable copy of the specified Collection.
*
* @param collection the collection to copy
* @return an immutable copy
*/
public static Collection immutableCollectionCopy(Collection collection) {
if (collection == null) return null;
if (collection.isEmpty()) return Collections.emptySet();
if (collection.size() == 1) return Collections.singleton(collection.iterator().next());
return new ImmutableCollectionWrapper<>(new ArrayList<>(collection));
}
/**
* Wraps a collection with an immutable collection. There is no copying involved.
*
* @param collection the collection to wrap
* @return an immutable collection wrapper that delegates to the original collection
*/
public static Collection immutableCollectionWrap(Collection extends T> collection) {
return new ImmutableCollectionWrapper<>(collection);
}
/**
* Wraps a {@link Map.Entry}} with an immutable {@link Map.Entry}}. There is no copying involved.
*
* @param entry the mapping to wrap.
* @return an immutable {@link Map.Entry}} wrapper that delegates to the original mapping.
*/
public static Map.Entry immutableEntry(Map.Entry entry) {
return new ImmutableEntry<>(entry);
}
/**
* Wraps a key and value with an immutable {@link Map.Entry}}. There is no copying involved.
*
* @param key the key to wrap.
* @param value the value to wrap.
* @return an immutable {@link Map.Entry}} wrapper that delegates to the original mapping.
*/
public static Map.Entry immutableEntry(K key, V value) {
return new ImmutableEntry<>(key, value);
}
public interface Immutable {
}
/*
* Immutable wrapper types.
*
* We have to re-implement Collections.unmodifiableXXX, since it is not
* simple to detect them (the class names are JDK dependent).
*/
public static class ImmutableIteratorWrapper implements Iterator {
private final Iterator extends E> iterator;
public ImmutableIteratorWrapper(Iterator extends E> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasNext() {
return iterator.hasNext();
}
@Override
public E next() {
return iterator.next();
}
// Use the default remove() implementation
@Override
public void forEachRemaining(Consumer super E> action) {
iterator.forEachRemaining(action);
}
}
private static class ImmutableCollectionWrapper implements Collection, Serializable, Immutable {
private static final long serialVersionUID = 6777564328198393535L;
Collection extends E> collection;
public ImmutableCollectionWrapper(Collection extends E> collection) {
this.collection = collection;
}
@Override
public boolean add(E o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends E> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o) {
return collection.contains(o);
}
@Override
public boolean containsAll(Collection> c) {
return collection.containsAll(c);
}
@Override
public boolean equals(Object o) {
return collection.equals(o);
}
@Override
public int hashCode() {
return collection.hashCode();
}
@Override
public boolean isEmpty() {
return collection.isEmpty();
}
@Override
public Iterator iterator() {
return new ImmutableIteratorWrapper<>(collection.iterator());
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> c) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return collection.size();
}
@Override
public Object[] toArray() {
return collection.toArray();
}
@Override
public T[] toArray(T[] a) {
return collection.toArray(a);
}
@Override
public String toString() {
return collection.toString();
}
}
/**
* Immutable version of Map.Entry for traversing immutable collections.
*/
private static class ImmutableEntry implements Entry, Immutable {
private final K key;
private final V value;
private final int hash;
ImmutableEntry(Entry extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
this.hash = entry.hashCode();
}
ImmutableEntry(K key, V value) {
this.key = key;
this.value = value;
this.hash = Objects.hashCode(key) ^ Objects.hashCode(value);
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V value) {
throw new UnsupportedOperationException();
}
private static boolean eq(Object o1, Object o2) {
return o1 == o2 || (o1 != null && o1.equals(o2));
}
@Override
@SuppressWarnings("unchecked")
public boolean equals(Object o) {
if (!(o instanceof Entry))
return false;
Entry entry = (Entry) o;
return eq(entry.getKey(), key) && eq(entry.getValue(), value);
}
@Override
public int hashCode() {
return hash;
}
@Override
public String toString() {
return getKey() + "=" + getValue();
}
}
private static class ImmutableSetWrapper extends ImmutableCollectionWrapper implements Set, Serializable, Immutable {
private static final long serialVersionUID = 7991492805176142615L;
public ImmutableSetWrapper(Set extends E> set) {
super(set);
}
}
private static class ImmutableEntrySetWrapper extends ImmutableSetWrapper> {
private static final long serialVersionUID = 6378667653889667692L;
@SuppressWarnings("unchecked")
public ImmutableEntrySetWrapper(Set extends Entry extends K, ? extends V>> set) {
super((Set>) set);
}
@Override
public Object[] toArray() {
Object[] array = new Object[collection.size()];
int i = 0;
for (Entry entry : this)
array[i++] = entry;
return array;
}
@Override
@SuppressWarnings("unchecked")
public T[] toArray(T[] array) {
int size = collection.size();
if (array.length < size)
array = (T[]) Array.newInstance(array.getClass().getComponentType(), size);
int i = 0;
Object[] result = array;
for (Entry entry : this)
result[i++] = entry;
return array;
}
@Override
public Iterator> iterator() {
return new ImmutableIteratorWrapper>(collection.iterator()) {
@Override
public Entry next() {
return new ImmutableEntry<>(super.next());
}
};
}
}
public static class ImmutableSetWrapperExternalizer extends AbstractExternalizer {
@Override
public void writeObject(ObjectOutput output, Set set) throws IOException {
MarshallUtil.marshallCollection(set, output);
}
@Override
public Set readObject(ObjectInput input) throws IOException, ClassNotFoundException {
Set
© 2015 - 2025 Weber Informatics LLC | Privacy Policy