All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.util.UnmodifiableMultiValueMap Maven / Gradle / Ivy

/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.util;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.springframework.lang.Nullable;

/**
 * Unmodifiable wrapper for {@link MultiValueMap}.
 *
 * @author Arjen Poutsma
 * @since 6.0
 * @param  the key type
 * @param  the value element type
 */
final class UnmodifiableMultiValueMap implements MultiValueMap, Serializable {

	private static final long serialVersionUID = -8697084563854098920L;

	@SuppressWarnings("serial")
	private final MultiValueMap delegate;

	@Nullable
	private transient Set keySet;

	@Nullable
	private transient Set>> entrySet;

	@Nullable
	private transient Collection> values;


	@SuppressWarnings("unchecked")
	public UnmodifiableMultiValueMap(MultiValueMap delegate) {
		Assert.notNull(delegate, "Delegate must not be null");
		this.delegate = (MultiValueMap) delegate;
	}

	// delegation

	@Override
	public int size() {
		return this.delegate.size();
	}

	@Override
	public boolean isEmpty() {
		return this.delegate.isEmpty();
	}

	@Override
	public boolean containsKey(Object key) {
		return this.delegate.containsKey(key);
	}

	@Override
	public boolean containsValue(Object value) {
		return this.delegate.containsValue(value);
	}

	@Override
	@Nullable
	public List get(Object key) {
		List result = this.delegate.get(key);
		return result != null ? Collections.unmodifiableList(result) : null;
	}

	@Override
	public V getFirst(K key) {
		return this.delegate.getFirst(key);
	}

	@Override
	public List getOrDefault(Object key, List defaultValue) {
		List result = this.delegate.getOrDefault(key, defaultValue);
		if (result != defaultValue) {
			result = Collections.unmodifiableList(result);
		}
		return result;
	}

	@Override
	public void forEach(BiConsumer> action) {
		this.delegate.forEach((k, vs) -> action.accept(k, Collections.unmodifiableList(vs)));
	}

	@Override
	public Map toSingleValueMap() {
		return this.delegate.toSingleValueMap();
	}

	@Override
	public int hashCode() {
		return this.delegate.hashCode();
	}

	@Override
	public boolean equals(Object obj) {
		return this == obj || this.delegate.equals(obj);
	}

	@Override
	public String toString() {
		return this.delegate.toString();
	}

	// lazy init

	@Override
	public Set keySet() {
		if (this.keySet == null) {
			this.keySet = Collections.unmodifiableSet(this.delegate.keySet());
		}
		return this.keySet;
	}

	@Override
	public Set>> entrySet() {
		if (this.entrySet == null) {
			this.entrySet = new UnmodifiableEntrySet<>(this.delegate.entrySet());
		}
		return this.entrySet;
	}

	@Override
	public Collection> values() {
		if (this.values == null) {
			this.values = new UnmodifiableValueCollection<>(this.delegate.values());
		}
		return this.values;
	}

	// unsupported

	@Nullable
	@Override
	public List put(K key, List value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List putIfAbsent(K key, List value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void putAll(Map> m) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List remove(Object key) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void add(K key, @Nullable V value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void addAll(K key, List values) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void addAll(MultiValueMap values) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void addIfAbsent(K key, @Nullable V value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void set(K key, @Nullable V value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void setAll(Map values) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void replaceAll(BiFunction, ? extends List> function) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean remove(Object key, Object value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean replace(K key, List oldValue, List newValue) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List replace(K key, List value) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List computeIfAbsent(K key, Function> mappingFunction) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List computeIfPresent(K key,
			BiFunction, ? extends List> remappingFunction) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List compute(K key,
			BiFunction, ? extends List> remappingFunction) {
		throw new UnsupportedOperationException();
	}

	@Override
	public List merge(K key, List value,
			BiFunction, ? super List, ? extends List> remappingFunction) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void clear() {
		throw new UnsupportedOperationException();
	}


	private static class UnmodifiableEntrySet implements Set>>, Serializable {

		private static final long serialVersionUID = 2407578793783925203L;

		@SuppressWarnings("serial")
		private final Set>> delegate;


		@SuppressWarnings("unchecked")
		public UnmodifiableEntrySet(Set>> delegate) {
			this.delegate = (Set>>) delegate;
		}

		// delegation

		@Override
		public int size() {
			return this.delegate.size();
		}

		@Override
		public boolean isEmpty() {
			return this.delegate.isEmpty();
		}

		@Override
		public boolean contains(Object o) {
			return this.delegate.contains(o);
		}

		@Override
		public boolean containsAll(Collection c) {
			return this.delegate.containsAll(c);
		}

		@Override
		public Iterator>> iterator() {
			Iterator>> iterator = this.delegate.iterator();
			return new Iterator<>() {
				@Override
				public boolean hasNext() {
					return iterator.hasNext();
				}

				@Override
				public Entry> next() {
					return new UnmodifiableEntry<>(iterator.next());
				}
			};
		}

		@Override
		public Object[] toArray() {
			Object[] result = this.delegate.toArray();
			filterArray(result);
			return result;
		}

		@Override
		public  T[] toArray(T[] a) {
			T[] result = this.delegate.toArray(a);
			filterArray(result);
			return result;
		}

		@SuppressWarnings("unchecked")
		private void filterArray(Object[] result) {
			for (int i = 0; i < result.length; i++) {
				if (result[i] instanceof Map.Entry entry) {
					result[i] = new UnmodifiableEntry<>((Entry>) entry);
				}
			}
		}

		@Override
		public void forEach(Consumer>> action) {
			this.delegate.forEach(e -> action.accept(new UnmodifiableEntry<>(e)));
		}

		@Override
		public Stream>> stream() {
			return StreamSupport.stream(spliterator(), false);
		}

		@Override
		public Stream>> parallelStream() {
			return StreamSupport.stream(spliterator(), true);
		}

		@Override
		public Spliterator>> spliterator() {
			return new UnmodifiableEntrySpliterator<>(this.delegate.spliterator());
		}

		@Override
		public int hashCode() {
			return this.delegate.hashCode();
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj) {
				return true;
			}
			else if (obj instanceof Set other) {
				return other.size() == this.delegate.size() &&
						containsAll(other);
			}
			return false;
		}

		@Override
		public String toString() {
			return this.delegate.toString();
		}

		// unsupported

		@Override
		public boolean add(Entry> kListEntry) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean remove(Object o) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeIf(Predicate>> filter) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean addAll(Collection>> c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean retainAll(Collection c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeAll(Collection c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void clear() {
			throw new UnsupportedOperationException();
		}


		private static class UnmodifiableEntrySpliterator implements Spliterator>> {

			private final Spliterator>> delegate;


			@SuppressWarnings("unchecked")
			public UnmodifiableEntrySpliterator(
					Spliterator>> delegate) {
				this.delegate = (Spliterator>>) delegate;
			}

			@Override
			public boolean tryAdvance(Consumer>> action) {
				return this.delegate.tryAdvance(entry -> action.accept(new UnmodifiableEntry<>(entry)));
			}

			@Override
			public void forEachRemaining(Consumer>> action) {
				this.delegate.forEachRemaining(entry -> action.accept(new UnmodifiableEntry<>(entry)));
			}

			@Override
			@Nullable
			public Spliterator>> trySplit() {
				Spliterator>> split = this.delegate.trySplit();
				if (split != null) {
					return new UnmodifiableEntrySpliterator<>(split);
				}
				else {
					return null;
				}
			}

			@Override
			public long estimateSize() {
				return this.delegate.estimateSize();
			}

			@Override
			public long getExactSizeIfKnown() {
				return this.delegate.getExactSizeIfKnown();
			}

			@Override
			public int characteristics() {
				return this.delegate.characteristics();
			}

			@Override
			public boolean hasCharacteristics(int characteristics) {
				return this.delegate.hasCharacteristics(characteristics);
			}

			@Override
			public Comparator>> getComparator() {
				return this.delegate.getComparator();
			}
		}


		private static class UnmodifiableEntry implements Map.Entry> {

			private final Entry> delegate;


			@SuppressWarnings("unchecked")
			public UnmodifiableEntry(Entry> delegate) {
				Assert.notNull(delegate, "Delegate must not be null");
				this.delegate = (Entry>) delegate;
			}

			@Override
			public K getKey() {
				return this.delegate.getKey();
			}

			@Override
			public List getValue() {
				return Collections.unmodifiableList(this.delegate.getValue());
			}

			@Override
			public List setValue(List value) {
				throw new UnsupportedOperationException();
			}

			@Override
			public int hashCode() {
				return this.delegate.hashCode();
			}

			@Override
			public boolean equals(Object obj) {
				if (this == obj) {
					return true;
				}
				else if (obj instanceof Map.Entry other) {
					return getKey().equals(other.getKey()) &&
							getValue().equals(other.getValue());
				}
				return false;
			}

			@Override
			public String toString() {
				return this.delegate.toString();
			}
		}
	}


	private static class UnmodifiableValueCollection implements Collection>, Serializable {

		private static final long serialVersionUID = 5518377583904339588L;

		@SuppressWarnings("serial")
		private final Collection> delegate;


		public UnmodifiableValueCollection(Collection> delegate) {
			this.delegate = delegate;
		}

		 // delegation

		@Override
		public int size() {
			return this.delegate.size();
		}

		@Override
		public boolean isEmpty() {
			return this.delegate.isEmpty();
		}

		@Override
		public boolean contains(Object o) {
			return this.delegate.contains(o);
		}

		@Override
		public boolean containsAll(Collection c) {
			return this.delegate.containsAll(c);
		}

		@Override
		public Object[] toArray() {
			Object[] result = this.delegate.toArray();
			filterArray(result);
			return result;
		}

		@Override
		public  T[] toArray(T[] a) {
			T[] result = this.delegate.toArray(a);
			filterArray(result);
			return result;
		}

		private void filterArray(Object[] array) {
			for (int i = 0; i < array.length; i++) {
				if (array[i] instanceof List list) {
					array[i] = Collections.unmodifiableList(list);
				}
			}
		}

		@Override
		public Iterator> iterator() {
			Iterator> iterator = this.delegate.iterator();
			return new Iterator<>() {
				@Override
				public boolean hasNext() {
					return iterator.hasNext();
				}

				@Override
				public List next() {
					return Collections.unmodifiableList(iterator.next());
				}
			};
		}

		@Override
		public void forEach(Consumer> action) {
			this.delegate.forEach(list -> action.accept(Collections.unmodifiableList(list)));
		}

		@Override
		public Spliterator> spliterator() {
			return new UnmodifiableValueSpliterator<>(this.delegate.spliterator());
		}

		@Override
		public Stream> stream() {
			return StreamSupport.stream(spliterator(), false);
		}

		@Override
		public Stream> parallelStream() {
			return StreamSupport.stream(spliterator(), true);
		}

		@Override
		public int hashCode() {
			return this.delegate.hashCode();
		}

		@Override
		public boolean equals(Object obj) {
			return this == obj || this.delegate.equals(obj);
		}

		@Override
		public String toString() {
			return this.delegate.toString();
		}

		// unsupported

		@Override
		public boolean add(List ts) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean remove(Object o) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean addAll(Collection> c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeAll(Collection c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean retainAll(Collection c) {
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean removeIf(Predicate> filter) {
			throw new UnsupportedOperationException();
		}

		@Override
		public void clear() {
			throw new UnsupportedOperationException();
		}


		private static class UnmodifiableValueSpliterator implements Spliterator> {

			private final Spliterator> delegate;


			public UnmodifiableValueSpliterator(Spliterator> delegate) {
				this.delegate = delegate;
			}

			@Override
			public boolean tryAdvance(Consumer> action) {
				return this.delegate.tryAdvance(l -> action.accept(Collections.unmodifiableList(l)));
			}

			@Override
			public void forEachRemaining(Consumer> action) {
				this.delegate.forEachRemaining(l -> action.accept(Collections.unmodifiableList(l)));
			}

			@Override
			@Nullable
			public Spliterator> trySplit() {
				Spliterator> split = this.delegate.trySplit();
				if (split != null) {
					return new UnmodifiableValueSpliterator<>(split);
				}
				else {
					return null;
				}
			}

			@Override
			public long estimateSize() {
				return this.delegate.estimateSize();
			}

			@Override
			public long getExactSizeIfKnown() {
				return this.delegate.getExactSizeIfKnown();
			}

			@Override
			public int characteristics() {
				return this.delegate.characteristics();
			}

			@Override
			public boolean hasCharacteristics(int characteristics) {
				return this.delegate.hasCharacteristics(characteristics);
			}

			@Override
			public Comparator> getComparator() {
				return this.delegate.getComparator();
			}
		}

	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy