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.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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 InfinispanCollections.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
* @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);
}
/**
* 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 InfinispanCollections.emptySet();
if (set.size() == 1) return Collections.singleton(set.iterator().next());
Set extends T> copy = ObjectDuplicator.duplicateSet(set);
if (copy == null)
// Set uses Collection copy-ctor
copy = attemptCopyConstructor(set, Collection.class);
if (copy == null)
copy = new HashSet(set);
return new ImmutableSetWrapper(copy);
}
/**
* 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 InfinispanCollections.emptyMap();
if (map.size() == 1) {
Map.Entry me = map.entrySet().iterator().next();
return Collections.singletonMap(me.getKey(), me.getValue());
}
Map extends K, ? extends V> copy = ObjectDuplicator.duplicateMap(map);
if (copy == null)
copy = attemptCopyConstructor(map, Map.class);
if (copy == null)
copy = new HashMap(map);
return new ImmutableMapWrapper(copy);
}
/**
* 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 InfinispanCollections.emptySet();
if (collection.size() == 1) return Collections.singleton(collection.iterator().next());
Collection extends T> copy = ObjectDuplicator.duplicateCollection(collection);
if (copy == null)
copy = attemptCopyConstructor(collection, Collection.class);
if (copy == null)
copy = new ArrayList(collection);
return new ImmutableCollectionWrapper(copy);
}
/**
* 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);
}
@SuppressWarnings("unchecked")
private static T attemptCopyConstructor(T source, Class super T> clazz) {
try {
return (T) source.getClass().getConstructor(clazz).newInstance(source);
}
catch (Exception e) {
}
return null;
}
/**
* 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);
}
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).
*/
private static class ImmutableIteratorWrapper implements Iterator {
private 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();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
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 K key;
private V value;
private int hash;
ImmutableEntry(Entry extends K, ? extends V> entry) {
this.key = entry.getKey();
this.value = entry.getValue();
this.hash = entry.hashCode();
}
@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 ImmutableReversibleOrderedSetWrapper extends ImmutableCollectionWrapper implements ReversibleOrderedSet, Serializable, Immutable {
private static final long serialVersionUID = 7991492805176142615L;
public ImmutableReversibleOrderedSetWrapper(Set extends E> set) {
super(set);
}
@Override
public Iterator reverseIterator() {
return new ImmutableIteratorWrapper(((ReversibleOrderedSet extends E>) collection).reverseIterator());
}
}
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());
}
};
}
}
private static class ImmutableMapWrapper implements Map, Serializable, Immutable {
private static final long serialVersionUID = 708144227046742221L;
private Map extends K, ? extends V> map;
public ImmutableMapWrapper(Map extends K, ? extends V> map) {
this.map = map;
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public Set> entrySet() {
return new ImmutableEntrySetWrapper(map.entrySet());
}
@Override
public boolean equals(Object o) {
return map.equals(o);
}
@Override
public V get(Object key) {
return map.get(key);
}
@Override
public int hashCode() {
return map.hashCode();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public Set keySet() {
return new ImmutableSetWrapper(map.keySet());
}
@Override
public V put(K key, V value) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map extends K, ? extends V> t) {
throw new UnsupportedOperationException();
}
@Override
public V remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public int size() {
return map.size();
}
@Override
public Collection values() {
return new ImmutableCollectionWrapper(map.values());
}
@Override
public String toString() {
return map.toString();
}
}
public static class ImmutableMapWrapperExternalizer extends AbstractExternalizer
© 2015 - 2025 Weber Informatics LLC | Privacy Policy