Browse Source
This commit introduces composite collections (i.e. Collection, Set, Map) and uses these composites in request predicates, where before new collections were instantiated. Closes gh-32245pull/32313/head
9 changed files with 953 additions and 53 deletions
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.lang.reflect.Array; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
|
||||
/** |
||||
* Composite collection that combines two other collections. This type is only |
||||
* exposed through {@link CompositeMap#values()}. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 6.2 |
||||
* @param <E> the type of elements maintained by this collection |
||||
*/ |
||||
class CompositeCollection<E> implements Collection<E> { |
||||
|
||||
private final Collection<E> first; |
||||
|
||||
private final Collection<E> second; |
||||
|
||||
|
||||
CompositeCollection(Collection<E> first, Collection<E> second) { |
||||
Assert.notNull(first, "First must not be null"); |
||||
Assert.notNull(second, "Second must not be null"); |
||||
this.first = first; |
||||
this.second = second; |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return this.first.size() + this.second.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return this.first.isEmpty() && this.second.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(Object o) { |
||||
if (this.first.contains(o)) { |
||||
return true; |
||||
} |
||||
else { |
||||
return this.second.contains(o); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
CompositeIterator<E> iterator = new CompositeIterator<>(); |
||||
iterator.add(this.first.iterator()); |
||||
iterator.add(this.second.iterator()); |
||||
return iterator; |
||||
} |
||||
|
||||
@Override |
||||
public Object[] toArray() { |
||||
Object[] result = new Object[size()]; |
||||
Object[] firstArray = this.first.toArray(); |
||||
Object[] secondArray = this.second.toArray(); |
||||
System.arraycopy(firstArray, 0, result, 0, firstArray.length); |
||||
System.arraycopy(secondArray, 0, result, firstArray.length, secondArray.length); |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
@SuppressWarnings("unchecked") |
||||
public <T> T[] toArray(T[] a) { |
||||
int size = this.size(); |
||||
T[] result; |
||||
if (a.length >= size) { |
||||
result = a; |
||||
} |
||||
else { |
||||
result = (T[]) Array.newInstance(a.getClass().getComponentType(), size); |
||||
} |
||||
|
||||
int idx = 0; |
||||
for (E e : this) { |
||||
result[idx++] = (T) e; |
||||
} |
||||
if (result.length > size) { |
||||
result[size] = null; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(E e) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(Object o) { |
||||
boolean firstResult = this.first.remove(o); |
||||
boolean secondResult = this.second.remove(o); |
||||
return firstResult || secondResult; |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsAll(Collection<?> c) { |
||||
for (Object o : c) { |
||||
if (!contains(o)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(Collection<? extends E> c) { |
||||
boolean changed = false; |
||||
for (E e : c) { |
||||
if (add(e)) { |
||||
changed = true; |
||||
} |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(Collection<?> c) { |
||||
if (c.isEmpty()) { |
||||
return false; |
||||
} |
||||
boolean firstResult = this.first.removeAll(c); |
||||
boolean secondResult = this.second.removeAll(c); |
||||
|
||||
return firstResult || secondResult; |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(Collection<?> c) { |
||||
boolean firstResult = this.first.retainAll(c); |
||||
boolean secondResult = this.second.retainAll(c); |
||||
|
||||
return firstResult || secondResult; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
this.first.clear(); |
||||
this.second.clear(); |
||||
} |
||||
} |
||||
@ -0,0 +1,189 @@
@@ -0,0 +1,189 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.function.BiFunction; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.springframework.lang.Nullable; |
||||
|
||||
/** |
||||
* Composite map that combines two other maps. This type is created via |
||||
* {@link CollectionUtils#compositeMap(Map, Map, BiFunction, Consumer)}. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 6.2 |
||||
* @param <K> the type of keys maintained by this map |
||||
* @param <V> the type of mapped values |
||||
*/ |
||||
final class CompositeMap<K, V> implements Map<K, V> { |
||||
|
||||
private final Map<K,V> first; |
||||
|
||||
private final Map<K,V> second; |
||||
|
||||
@Nullable |
||||
private final BiFunction<K,V,V> putFunction; |
||||
|
||||
@Nullable |
||||
private final Consumer<Map<K, V>> putAllFunction; |
||||
|
||||
|
||||
CompositeMap(Map<K, V> first, Map<K, V> second) { |
||||
this(first, second, null, null); |
||||
} |
||||
|
||||
CompositeMap(Map<K, V> first, Map<K, V> second, |
||||
@Nullable BiFunction<K, V, V> putFunction, |
||||
@Nullable Consumer<Map<K,V>> putAllFunction) { |
||||
|
||||
Assert.notNull(first, "First must not be null"); |
||||
Assert.notNull(second, "Second must not be null"); |
||||
this.first = first; |
||||
this.second = second; |
||||
this.putFunction = putFunction; |
||||
this.putAllFunction = putAllFunction; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int size() { |
||||
return this.first.size() + this.second.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return this.first.isEmpty() && this.second.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsKey(Object key) { |
||||
if (this.first.containsKey(key)) { |
||||
return true; |
||||
} |
||||
else { |
||||
return this.second.containsKey(key); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsValue(Object value) { |
||||
if (this.first.containsValue(value)) { |
||||
return true; |
||||
} |
||||
else { |
||||
return this.second.containsValue(value); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public V get(Object key) { |
||||
V firstResult = this.first.get(key); |
||||
if (firstResult != null) { |
||||
return firstResult; |
||||
} |
||||
else { |
||||
return this.second.get(key); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public V put(K key, V value) { |
||||
if (this.putFunction == null) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
else { |
||||
return this.putFunction.apply(key, value); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public V remove(Object key) { |
||||
V firstResult = this.first.remove(key); |
||||
V secondResult = this.second.remove(key); |
||||
if (firstResult != null) { |
||||
return firstResult; |
||||
} |
||||
else { |
||||
return secondResult; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
@SuppressWarnings("unchecked") |
||||
public void putAll(Map<? extends K, ? extends V> m) { |
||||
if (this.putAllFunction != null) { |
||||
this.putAllFunction.accept((Map<K, V>) m); |
||||
} |
||||
else { |
||||
for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) { |
||||
put(e.getKey(), e.getValue()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
this.first.clear(); |
||||
this.second.clear(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<K> keySet() { |
||||
return new CompositeSet<>(this.first.keySet(), this.second.keySet()); |
||||
} |
||||
|
||||
@Override |
||||
public Collection<V> values() { |
||||
return new CompositeCollection<>(this.first.values(), this.second.values()); |
||||
} |
||||
|
||||
@Override |
||||
public Set<Entry<K, V>> entrySet() { |
||||
return new CompositeSet<>(this.first.entrySet(), this.second.entrySet()); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
Iterator<Entry<K, V>> i = entrySet().iterator(); |
||||
if (!i.hasNext()) { |
||||
return "{}"; |
||||
} |
||||
|
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.append('{'); |
||||
while (true) { |
||||
Entry<K, V> e = i.next(); |
||||
K key = e.getKey(); |
||||
V value = e.getValue(); |
||||
sb.append(key == this ? "(this Map)" : key); |
||||
sb.append('='); |
||||
sb.append(value == this ? "(this Map)" : value); |
||||
if (!i.hasNext()) { |
||||
return sb.append('}').toString(); |
||||
} |
||||
sb.append(',').append(' '); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
@@ -0,0 +1,67 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.util.Set; |
||||
|
||||
/** |
||||
* Composite set that combines two other sets. This type is only exposed through |
||||
* {@link CompositeMap#keySet()} and {@link CompositeMap#entrySet()}. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 6.2 |
||||
* @param <E> the type of elements maintained by this set |
||||
*/ |
||||
final class CompositeSet<E> extends CompositeCollection<E> implements Set<E> { |
||||
|
||||
CompositeSet(Set<E> first, Set<E> second) { |
||||
super(first, second); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean equals(Object obj) { |
||||
if (obj == this) { |
||||
return true; |
||||
} |
||||
else if (obj instanceof Set<?> set) { |
||||
if (set.size() != size()) { |
||||
return false; |
||||
} |
||||
try { |
||||
return containsAll(set); |
||||
} |
||||
catch (ClassCastException | NullPointerException ignored) { |
||||
return false; |
||||
} |
||||
} |
||||
else { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
int hashCode = 0; |
||||
for (E obj : this) { |
||||
if (obj != null) { |
||||
hashCode += obj.hashCode(); |
||||
} |
||||
} |
||||
return hashCode; |
||||
} |
||||
} |
||||
@ -0,0 +1,195 @@
@@ -0,0 +1,195 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
|
||||
/** |
||||
* @author Arjen Poutsma |
||||
*/ |
||||
class CompositeCollectionTests { |
||||
|
||||
@Test |
||||
void size() { |
||||
List<String> first = List.of("foo", "bar", "baz"); |
||||
List<String> second = List.of("qux", "quux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThat(composite).hasSize(5); |
||||
} |
||||
|
||||
@Test |
||||
void isEmpty() { |
||||
List<String> first = List.of("foo", "bar", "baz"); |
||||
List<String> second = List.of("qux", "quux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThat(composite).isNotEmpty(); |
||||
|
||||
composite = new CompositeCollection<>(Collections.emptyList(), Collections.emptyList()); |
||||
assertThat(composite).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void contains() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThat(composite.contains("foo")).isTrue(); |
||||
assertThat(composite.contains("bar")).isTrue(); |
||||
assertThat(composite.contains("baz")).isTrue(); |
||||
assertThat(composite.contains("qux")).isTrue(); |
||||
assertThat(composite.contains("quux")).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void iterator() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
Iterator<String> iterator = composite.iterator(); |
||||
assertThat(iterator).hasNext(); |
||||
assertThat(iterator.next()).isEqualTo("foo"); |
||||
assertThat(iterator).hasNext(); |
||||
assertThat(iterator.next()).isEqualTo("bar"); |
||||
assertThat(iterator).hasNext(); |
||||
assertThat(iterator.next()).isEqualTo("baz"); |
||||
assertThat(iterator).hasNext(); |
||||
assertThat(iterator.next()).isEqualTo("qux"); |
||||
assertThat(iterator).isExhausted(); |
||||
} |
||||
|
||||
@Test |
||||
void toArray() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
Object[] array = composite.toArray(); |
||||
assertThat(array).containsExactly("foo", "bar", "baz", "qux"); |
||||
} |
||||
|
||||
@Test |
||||
void toArrayArgs() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
String[] array = new String[composite.size()]; |
||||
array = composite.toArray(array); |
||||
assertThat(array).containsExactly("foo", "bar", "baz", "qux"); |
||||
} |
||||
|
||||
@Test |
||||
void add() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> composite.add("quux")); |
||||
} |
||||
|
||||
@Test |
||||
void remove() { |
||||
List<String> first = new ArrayList<>(List.of("foo", "bar")); |
||||
List<String> second = new ArrayList<>(List.of("baz", "qux")); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThat(composite.remove("foo")).isTrue(); |
||||
assertThat(composite.contains("foo")).isFalse(); |
||||
assertThat(first).containsExactly("bar"); |
||||
|
||||
assertThat(composite.remove("quux")).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void containsAll() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
List<String> all = new ArrayList<>(first); |
||||
all.addAll(second); |
||||
|
||||
assertThat(composite.containsAll(all)).isTrue(); |
||||
|
||||
all.add("quux"); |
||||
|
||||
assertThat(composite.containsAll(all)).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void addAll() { |
||||
List<String> first = List.of("foo", "bar"); |
||||
List<String> second = List.of("baz", "qux"); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> composite.addAll(List.of("quux", "corge"))); |
||||
} |
||||
|
||||
@Test |
||||
void removeAll() { |
||||
List<String> first = new ArrayList<>(List.of("foo", "bar")); |
||||
List<String> second = new ArrayList<>(List.of("baz", "qux")); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
List<String> all = new ArrayList<>(first); |
||||
all.addAll(second); |
||||
|
||||
assertThat(composite.removeAll(all)).isTrue(); |
||||
|
||||
assertThat(composite).isEmpty(); |
||||
assertThat(first).isEmpty(); |
||||
assertThat(second).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void retainAll() { |
||||
List<String> first = new ArrayList<>(List.of("foo", "bar")); |
||||
List<String> second = new ArrayList<>(List.of("baz", "qux")); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
assertThat(composite.retainAll(List.of("bar", "baz"))).isTrue(); |
||||
|
||||
assertThat(composite).containsExactly("bar", "baz"); |
||||
assertThat(first).containsExactly("bar"); |
||||
assertThat(second).containsExactly("baz"); |
||||
} |
||||
|
||||
@Test |
||||
void clear() { |
||||
List<String> first = new ArrayList<>(List.of("foo", "bar")); |
||||
List<String> second = new ArrayList<>(List.of("baz", "qux")); |
||||
CompositeCollection<String> composite = new CompositeCollection<>(first, second); |
||||
|
||||
composite.clear(); |
||||
|
||||
assertThat(composite).isEmpty(); |
||||
assertThat(first).isEmpty(); |
||||
assertThat(second).isEmpty(); |
||||
} |
||||
} |
||||
@ -0,0 +1,221 @@
@@ -0,0 +1,221 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
||||
import static org.assertj.core.api.Assertions.entry; |
||||
|
||||
/** |
||||
* @author Arjen Poutsma |
||||
*/ |
||||
class CompositeMapTests { |
||||
|
||||
@Test |
||||
void size() { |
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux"); |
||||
Map<String, String> second = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite).hasSize(3); |
||||
} |
||||
|
||||
@Test |
||||
void isEmpty() { |
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux"); |
||||
Map<String, String> second = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite).isNotEmpty(); |
||||
|
||||
composite = new CompositeMap<>(Collections.emptyMap(), Collections.emptyMap()); |
||||
assertThat(composite).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void containsKey() { |
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux"); |
||||
Map<String, String> second = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite.containsKey("foo")).isTrue(); |
||||
assertThat(composite.containsKey("bar")).isFalse(); |
||||
assertThat(composite.containsKey("baz")).isTrue(); |
||||
assertThat(composite.containsKey("qux")).isFalse(); |
||||
assertThat(composite.containsKey("quux")).isTrue(); |
||||
assertThat(composite.containsKey("corge")).isFalse(); |
||||
} |
||||
|
||||
@Test |
||||
void containsValue() { |
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux"); |
||||
Map<String, String> second = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite.containsValue("foo")).isFalse(); |
||||
assertThat(composite.containsValue("bar")).isTrue(); |
||||
assertThat(composite.containsValue("baz")).isFalse(); |
||||
assertThat(composite.containsValue("qux")).isTrue(); |
||||
assertThat(composite.containsValue("quux")).isFalse(); |
||||
assertThat(composite.containsValue("corge")).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void get() { |
||||
Map<String, String> first = Map.of("foo", "bar", "baz", "qux"); |
||||
Map<String, String> second = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite.get("foo")).isEqualTo("bar"); |
||||
assertThat(composite.get("baz")).isEqualTo("qux"); |
||||
assertThat(composite.get("quux")).isEqualTo("corge"); |
||||
|
||||
assertThat(composite.get("grault")).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
void putUnsupported() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> composite.put("grault", "garply")); |
||||
} |
||||
@Test |
||||
void putSupported() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second, (k,v) -> { |
||||
assertThat(k).isEqualTo("quux"); |
||||
assertThat(v).isEqualTo("corge"); |
||||
return "grault"; |
||||
}, null); |
||||
|
||||
assertThat(composite.put("quux", "corge")).isEqualTo("grault"); |
||||
} |
||||
|
||||
@Test |
||||
void remove() { |
||||
Map<String, String> first = new HashMap<>(Map.of("foo", "bar", "baz", "qux")); |
||||
Map<String, String> second = new HashMap<>(Map.of("quux", "corge")); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThat(composite.remove("foo")).isEqualTo("bar"); |
||||
assertThat(composite.containsKey("foo")).isFalse(); |
||||
assertThat(first).containsExactly(entry("baz", "qux")); |
||||
|
||||
assertThat(composite.remove("grault")).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
void putAllUnsupported() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
|
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> composite.putAll(Map.of("quux", "corge", "grault", "garply"))); |
||||
} |
||||
|
||||
@Test |
||||
void putAllPutFunction() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
|
||||
AtomicBoolean functionInvoked = new AtomicBoolean(); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second, (k,v) -> { |
||||
assertThat(k).isEqualTo("quux"); |
||||
assertThat(v).isEqualTo("corge"); |
||||
functionInvoked.set(true); |
||||
return "grault"; |
||||
}, null); |
||||
|
||||
composite.putAll(Map.of("quux", "corge")); |
||||
|
||||
assertThat(functionInvoked).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void putAllPutAllFunction() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
|
||||
AtomicBoolean functionInvoked = new AtomicBoolean(); |
||||
Map<String, String> argument = Map.of("quux", "corge"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second, null, |
||||
m -> { |
||||
assertThat(m).isSameAs(argument); |
||||
functionInvoked.set(true); |
||||
}); |
||||
|
||||
composite.putAll(argument); |
||||
|
||||
assertThat(functionInvoked).isTrue(); |
||||
} |
||||
|
||||
@Test |
||||
void clear() { |
||||
Map<String, String> first = new HashMap<>(Map.of("foo", "bar", "baz", "qux")); |
||||
Map<String, String> second = new HashMap<>(Map.of("quux", "corge")); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
composite.clear(); |
||||
|
||||
assertThat(composite).isEmpty(); |
||||
assertThat(first).isEmpty(); |
||||
assertThat(second).isEmpty(); |
||||
} |
||||
|
||||
@Test |
||||
void keySet() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
Set<String> keySet = composite.keySet(); |
||||
assertThat(keySet).containsExactly("foo", "baz"); |
||||
} |
||||
|
||||
@Test |
||||
void values() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
Collection<String> values = composite.values(); |
||||
assertThat(values).containsExactly("bar", "qux"); |
||||
} |
||||
|
||||
@Test |
||||
void entrySet() { |
||||
Map<String, String> first = Map.of("foo", "bar"); |
||||
Map<String, String> second = Map.of("baz", "qux"); |
||||
CompositeMap<String, String> composite = new CompositeMap<>(first, second); |
||||
|
||||
Set<Map.Entry<String, String>> entries = composite.entrySet(); |
||||
assertThat(entries).containsExactly(entry("foo", "bar"), entry("baz", "qux")); |
||||
} |
||||
} |
||||
@ -0,0 +1,47 @@
@@ -0,0 +1,47 @@
|
||||
/* |
||||
* Copyright 2002-2024 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.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.Set; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* @author Arjen Poutsma |
||||
*/ |
||||
class CompositeSetTests { |
||||
|
||||
@Test |
||||
void testEquals() { |
||||
Set<String> first = Set.of("foo", "bar"); |
||||
Set<String> second = Set.of("baz", "qux"); |
||||
CompositeSet<String> composite = new CompositeSet<>(first, second); |
||||
|
||||
Set<String> all = new HashSet<>(first); |
||||
all.addAll(second); |
||||
|
||||
assertThat(composite.equals(all)).isTrue(); |
||||
assertThat(composite.equals(first)).isFalse(); |
||||
assertThat(composite.equals(second)).isFalse(); |
||||
assertThat(composite.equals(Collections.emptySet())).isFalse(); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue