From 166b2abedf2ff4e6f7a3c1e4e80b2a38df313902 Mon Sep 17 00:00:00 2001 From: andremoniy2 Date: Mon, 14 Feb 2022 00:42:09 +0100 Subject: [PATCH 1/3] Fix for JDK 17+ --- .../org/hamcrest/collection/IsUnmodifiableCollection.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java index ecc6184d..36da9170 100644 --- a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java +++ b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java @@ -140,7 +140,12 @@ public int compare(Constructor o1, Constructor o2) { } }); for (Constructor declaredConstructor : declaredConstructors) { - declaredConstructor.setAccessible(true); + try { + declaredConstructor.setAccessible(true); + } catch (Exception ignore) { + // Since Java 17 it is impossible to make jdk* classes accessible without manipulation with modules: + // module java.base does not "opens java.util" to unnamed module + } final int parametersNumber = declaredConstructor.getParameterTypes().length; Object[] arguments = new Object[parametersNumber]; From 24f01f819b60465aba56aa494f0a0a16910e4293 Mon Sep 17 00:00:00 2001 From: andremoniy2 Date: Thu, 17 Feb 2022 14:46:44 +0100 Subject: [PATCH 2/3] Fix for JDK 17+ --- .../collection/IsUnmodifiableCollection.java | 241 ++++++++++++--- .../IsUnmodifiableCollectionTest.java | 283 +++++++++++++----- 2 files changed, 419 insertions(+), 105 deletions(-) diff --git a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java index 36da9170..72030a5f 100644 --- a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java +++ b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java @@ -6,15 +6,7 @@ import java.lang.reflect.Array; import java.lang.reflect.Constructor; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Matches if collection is truly unmodifiable @@ -22,75 +14,233 @@ public class IsUnmodifiableCollection extends TypeSafeDiagnosingMatcher> { private static final Map DEFAULT_COLLECTIONS = new HashMap<>(); + private static final Set KNOWN_UNMODIFIABLE_COLLECTIONS = new HashSet<>(); static { final List list = Arrays.asList("a", "b", "c"); DEFAULT_COLLECTIONS.put(Collection.class, list); DEFAULT_COLLECTIONS.put(List.class, list); DEFAULT_COLLECTIONS.put(Set.class, new HashSet<>(list)); + + KNOWN_UNMODIFIABLE_COLLECTIONS.add("java.util.ImmutableCollections"); + KNOWN_UNMODIFIABLE_COLLECTIONS.add("java.util.Collections$Unmodifiable"); + } + + /** + * Creates matcher that matches when collection is truly unmodifiable + */ + public static Matcher> isUnmodifiable() { + return new IsUnmodifiableCollection<>(); } @SuppressWarnings("unchecked") @Override protected boolean matchesSafely(final Collection collection, final Description mismatchDescription) { final Class collectionClass = collection.getClass(); - final Collection item = getInstanceOfType(collectionClass); + String collectionClassName = collectionClass.getName(); + for (String knownUnmodifiableCollection : KNOWN_UNMODIFIABLE_COLLECTIONS) { + if (collectionClassName.startsWith(knownUnmodifiableCollection)) { + return true; + } + } + final Collection item = getInstanceOfType(collectionClass, collection); if (item == null) { throw failedToInstantiateItem(collectionClass, null); } final Object testObject = new Object(); final Set singletonList = Collections.singleton(testObject); + if (collection instanceof List) { + // This is an operation on the original collection, but it is safe, since it sets the same element + List originalList = (List) collection; + if (checkMethod_set(originalList, mismatchDescription)) return false; + + List copiedList = (List) item; + if (checkMethod_listIterator_remove(copiedList, mismatchDescription)) return false; + if (checkMethod_listIterator_set(copiedList, testObject, mismatchDescription)) return false; + if (checkMethod_listIterator_add(copiedList, testObject, mismatchDescription)) return false; + if (checkMethod_listIterator_index(copiedList, mismatchDescription)) return false; + if (checkMethod_add_index(copiedList, testObject, mismatchDescription)) return false; + if (checkMethod_add_all_index(copiedList, singletonList, mismatchDescription)) return false; + if (checkMethod_remove_index(copiedList, mismatchDescription)) return false; + } + + if (checkMethod_add(item, testObject, mismatchDescription)) return false; + if (checkMethod_add_all(item, singletonList, mismatchDescription)) return false; + if (checkMethod_remove(item, testObject, mismatchDescription)) return false; + if (checkMethod_remove_all(item, singletonList, mismatchDescription)) return false; + if (checkMethod_retail_all(item, singletonList, mismatchDescription)) return false; + if (checkMethod_clear(item, mismatchDescription)) return false; + if (checkMethod_iterator(item, mismatchDescription)) return false; + + return true; + } + + private boolean checkMethod_iterator(Collection item, Description mismatchDescription) { try { - item.add(testObject); - mismatchDescription.appendText("was able to add a value into the collection"); - return false; + Iterator iterator = item.iterator(); + iterator.remove(); + mismatchDescription.appendText("was able to remove an element from the iterator"); + return true; + } catch (Exception ignore) { + } + return false; + } + + private boolean checkMethod_clear(Collection item, Description mismatchDescription) { + try { + item.clear(); + mismatchDescription.appendText("was able to clear the collection"); + return true; } catch (Exception ignore) { } + return false; + } + + private boolean checkMethod_retail_all(Collection item, Set singletonList, Description mismatchDescription) { + try { + item.retainAll(singletonList); + mismatchDescription.appendText("was able to call retainAll on the collection"); + return true; + } catch (Exception ignore) { + } + return false; + } + + private boolean checkMethod_remove_all(Collection item, Set singletonList, Description mismatchDescription) { + try { + item.removeAll(singletonList); + mismatchDescription.appendText("was able to call removeAll on the collection"); + return true; + } catch (Exception ignore) { + } + return false; + } + private boolean checkMethod_remove(Collection item, Object testObject, Description mismatchDescription) { + try { + item.remove(testObject); + mismatchDescription.appendText("was able to call remove a value from the collection"); + return true; + } catch (Exception ignore) { + } + return false; + } + + private boolean checkMethod_remove_index(List item, Description mismatchDescription) { + try { + item.remove(0); + mismatchDescription.appendText("was able to call remove by index from the collection"); + return true; + } catch (Exception ignore) { + } + return false; + } + + private boolean checkMethod_add_all(Collection item, Set singletonList, Description mismatchDescription) { try { item.addAll(singletonList); mismatchDescription.appendText("was able to perform addAll on the collection"); - return false; + return true; } catch (Exception ignore) { } + return false; + } + private boolean checkMethod_add_all_index(List item, Set singletonList, Description mismatchDescription) { try { - item.remove(testObject); - mismatchDescription.appendText("was able to remove a value from the collection"); - return false; + item.addAll(0, singletonList); + mismatchDescription.appendText("was able to perform addAll by index on the collection"); + return true; } catch (Exception ignore) { } + return false; + } + private boolean checkMethod_add(Collection item, Object testObject, Description mismatchDescription) { try { - item.removeAll(singletonList); - mismatchDescription.appendText("was able to perform removeAll on the collection"); - return false; + item.add(testObject); + mismatchDescription.appendText("was able to add a value into the collection"); + return true; } catch (Exception ignore) { } + return false; + } + private boolean checkMethod_add_index(List item, Object testObject, Description mismatchDescription) { try { - item.retainAll(singletonList); - mismatchDescription.appendText("was able to perform retainAll on the collection"); - return false; + item.add(0, testObject); + mismatchDescription.appendText("was able to add a value into the list by index"); + return true; } catch (Exception ignore) { } + return false; + } + private boolean checkMethod_listIterator_remove(List item, Description mismatchDescription) { + List list = item; try { - item.clear(); - mismatchDescription.appendText("was able to clear the collection"); - return false; + ListIterator iterator = list.listIterator(); + iterator.remove(); + mismatchDescription.appendText("was able to remove an element from the list iterator"); + return true; } catch (Exception ignore) { } + return false; + } - return true; + private boolean checkMethod_listIterator_set(List item, Object testObject, Description mismatchDescription) { + List list = item; + try { + ListIterator iterator = list.listIterator(); + iterator.next(); + iterator.set(testObject); + mismatchDescription.appendText("was able to set element on the list iterator"); + return true; + } catch (Exception ignore) { + } + return false; } + private boolean checkMethod_listIterator_add(List item, Object testObject, Description mismatchDescription) { + List list = item; + try { + ListIterator iterator = list.listIterator(); + iterator.next(); + iterator.add(testObject); + mismatchDescription.appendText("was able to add element on the list iterator"); + return true; + } catch (Exception ignore) { + } + return false; + } - @SuppressWarnings("unchecked") - private T getInstanceOfType(final Class clazz) { - Exception lastException = null; + private boolean checkMethod_listIterator_index(List item, Description mismatchDescription) { + List list = item; + try { + Iterator iterator = list.listIterator(0); + iterator.remove(); + mismatchDescription.appendText("was able to remove an element from the list iterator with index"); + return true; + } catch (Exception ignore) { + } + return false; + } + + private boolean checkMethod_set(List list, Description mismatchDescription) { + if (list.size() > 0) { + try { + list.set(0, list.get(0)); + mismatchDescription.appendText("was able to set an element of the collection"); + return true; + } catch (Exception ignore) { + } + } + return false; + } + @SuppressWarnings("unchecked") + private T getInstanceOfType(final Class clazz, Collection collection) { if (clazz.isArray()) { return (T) Array.newInstance(clazz, 0); } @@ -132,6 +282,18 @@ private T getInstanceOfType(final Class clazz) { // For the most part of implementations there probably won't be any default constructor final Constructor[] declaredConstructors = clazz.getDeclaredConstructors(); + + Constructor constructorForCollection = findConstructorForCollection(declaredConstructors); + + Exception lastException = null; + if (constructorForCollection != null) { + try { + return (T) constructorForCollection.newInstance(collection); + } catch (Exception e) { + lastException = e; + } + } + // First take constructor with fewer number of arguments Arrays.sort(declaredConstructors, new Comparator>() { @Override @@ -139,6 +301,7 @@ public int compare(Constructor o1, Constructor o2) { return Integer.compare(o2.getParameterTypes().length, o1.getParameterTypes().length); } }); + for (Constructor declaredConstructor : declaredConstructors) { try { declaredConstructor.setAccessible(true); @@ -150,7 +313,7 @@ public int compare(Constructor o1, Constructor o2) { Object[] arguments = new Object[parametersNumber]; for (int argumentIndex = 0; argumentIndex < arguments.length; argumentIndex++) { - arguments[argumentIndex] = getInstanceOfType(declaredConstructor.getParameterTypes()[argumentIndex]); + arguments[argumentIndex] = getInstanceOfType(declaredConstructor.getParameterTypes()[argumentIndex], collection); } try { return (T) declaredConstructor.newInstance(arguments); @@ -162,6 +325,15 @@ public int compare(Constructor o1, Constructor o2) { throw failedToInstantiateItem(clazz, lastException); } + private Constructor findConstructorForCollection(Constructor[] declaredConstructors) { + for (Constructor constructor : declaredConstructors) { + if (constructor.getParameterTypes().length == 1 && constructor.getParameterTypes()[0].isAssignableFrom(Collection.class)) { + return constructor; + } + } + return null; + } + private IllegalStateException failedToInstantiateItem(Class clazz, Exception e) { return new IllegalStateException("Failed to create an instance of <" + clazz + "> class.", e); } @@ -171,11 +343,4 @@ public void describeTo(Description description) { description.appendText("Expected to be unmodifiable collection, but "); } - /** - * Creates matcher that matches when collection is truly unmodifiable - */ - public static Matcher> isUnmodifiable() { - return new IsUnmodifiableCollection<>(); - } - } diff --git a/hamcrest/src/test/java/org/hamcrest/collection/IsUnmodifiableCollectionTest.java b/hamcrest/src/test/java/org/hamcrest/collection/IsUnmodifiableCollectionTest.java index 2d822ab9..b73f918a 100644 --- a/hamcrest/src/test/java/org/hamcrest/collection/IsUnmodifiableCollectionTest.java +++ b/hamcrest/src/test/java/org/hamcrest/collection/IsUnmodifiableCollectionTest.java @@ -3,16 +3,35 @@ import org.hamcrest.AbstractMatcherTest; import org.hamcrest.Matcher; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; +import java.util.*; import static org.hamcrest.collection.IsUnmodifiableCollection.isUnmodifiable; public class IsUnmodifiableCollectionTest extends AbstractMatcherTest { + private static final String SET_INT_INDEX_E_ELEMENT = "set(int index, E element)"; + private static final String ADD_E_E = "add(E e)"; + private static final String ADD_INT_INDEX_E_ELEMENT = "add(int index, E element)"; + private static final String REMOVE_INT_INDEX = "remove(int index)"; + private static final String REMOVE_OBJECT_O = "remove(Object o)"; + private static final String ADD_ALL_COLLECTION_EXTENDS_E_C = "addAll(Collection c)"; + private static final String ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C = "addAll(int index, Collection c)"; + private static final String REMOVE_ALL_COLLECTION_C = "removeAll(Collection c)"; + private static final String RETAIN_ALL_COLLECTION_C = "retainAll(Collection c)"; + private static final String CLEAR = "clear()"; + private static final List ERROR_CONDITIONS = Arrays.asList( + new String[]{"was able to add element on the list iterator", SET_INT_INDEX_E_ELEMENT}, + new String[]{"was able to perform addAll by index on the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT}, + new String[]{"was able to call remove by index from the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C}, + new String[]{"was able to add a value into the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX}, + new String[]{"was able to perform addAll on the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E}, + new String[]{"was able to call remove a value from the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E, ADD_ALL_COLLECTION_EXTENDS_E_C}, + new String[]{"was able to call removeAll on the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E, ADD_ALL_COLLECTION_EXTENDS_E_C, REMOVE_OBJECT_O}, + new String[]{"was able to call retainAll on the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E, ADD_ALL_COLLECTION_EXTENDS_E_C, REMOVE_OBJECT_O, REMOVE_ALL_COLLECTION_C}, + new String[]{"was able to clear the collection", SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E, ADD_ALL_COLLECTION_EXTENDS_E_C, REMOVE_OBJECT_O, REMOVE_ALL_COLLECTION_C, RETAIN_ALL_COLLECTION_C}, + new String[]{null, SET_INT_INDEX_E_ELEMENT, ADD_INT_INDEX_E_ELEMENT, ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C, REMOVE_INT_INDEX, ADD_E_E, ADD_ALL_COLLECTION_EXTENDS_E_C, REMOVE_OBJECT_O, REMOVE_ALL_COLLECTION_C, RETAIN_ALL_COLLECTION_C, CLEAR} + ); + @Override protected Matcher createMatcher() { return isUnmodifiable(); @@ -22,119 +41,249 @@ public void testMatchesUnmodifiableList() { assertMatches("truly unmodifiable list", isUnmodifiable(), Collections.unmodifiableList(Collections.emptyList())); } - public void testMatchesUnmodifiableSet() { - assertMatches("truly unmodifiable set", isUnmodifiable(), Collections.unmodifiableSet(Collections.emptySet())); - } + public void testMatchesUnmodifiableCustomList() { + class CustomUnmodifiableList implements List { - public void testMatchesUnmodifiableCollection() { - assertMatches("truly unmodifiable collection", isUnmodifiable(), Collections.unmodifiableCollection(Arrays.asList(1,2,3))); - } + private List list; - public void testMismatchesArrayList() { - assertMismatchDescription("was able to add a value into the collection", isUnmodifiable(), new ArrayList<>()); - } + public CustomUnmodifiableList(List list) { + this.list = Collections.unmodifiableList(list); + } - public void testMismatchesArraysList() { - assertMismatchDescription("was able to remove a value from the collection", isUnmodifiable(), Arrays.asList(1,2,3)); - } + @Override + public int size() { + return list.size(); + } - public void testMismatchesHashSet() { - assertMismatchDescription("was able to add a value into the collection", isUnmodifiable(), new HashSet<>()); - } + @Override + public boolean isEmpty() { + return list.isEmpty(); + } - public void testMismatchesPartiallyUnmodifiableListAllowingAddAll() { - assertMismatchDescription("was able to perform addAll on the collection", isUnmodifiable(), new ArrayList() { @Override - public boolean add(String s) { - throw new UnsupportedOperationException(); + public boolean contains(Object o) { + return list.contains(o); } - }); - } - public void testMismatchesPartiallyUnmodifiableListAllowingRemove() { - assertMismatchDescription("was able to remove a value from the collection", isUnmodifiable(), new ArrayList() { @Override - public boolean add(String s) { - throw new UnsupportedOperationException(); + public Iterator iterator() { + return list.iterator(); } @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); + public Object[] toArray() { + return list.toArray(); } - }); - } - public void testMismatchesPartiallyUnmodifiableListAllowingRemoveAll() { - assertMismatchDescription("was able to perform removeAll on the collection", isUnmodifiable(), new ArrayList() { @Override - public boolean add(String s) { - throw new UnsupportedOperationException(); + public T[] toArray(T[] a) { + return list.toArray(a); } @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); + public boolean add(E e) { + return list.add(e); } @Override public boolean remove(Object o) { - throw new UnsupportedOperationException(); + return list.remove(o); } - }); - } - public void testMismatchesPartiallyUnmodifiableListAllowingRetainAll() { - assertMismatchDescription("was able to perform retainAll on the collection", isUnmodifiable(), new ArrayList() { @Override - public boolean add(String s) { - throw new UnsupportedOperationException(); + public boolean containsAll(Collection c) { + return list.containsAll(c); } @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); + public boolean addAll(Collection c) { + return list.addAll(c); } @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); + public boolean addAll(int index, Collection c) { + return list.addAll(index, c); } @Override public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(); + return list.removeAll(c); } - }); - } - public void testMismatchesPartiallyUnmodifiableListAllowingClear() { - assertMismatchDescription("was able to clear the collection", isUnmodifiable(), new ArrayList() { @Override - public boolean add(String s) { - throw new UnsupportedOperationException(); + public boolean retainAll(Collection c) { + return list.retainAll(c); } @Override - public boolean addAll(Collection c) { - throw new UnsupportedOperationException(); + public void clear() { + list.clear(); } @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException(); + public E get(int index) { + return list.get(index); } @Override - public boolean removeAll(Collection c) { - throw new UnsupportedOperationException(); + public E set(int index, E element) { + return list.set(index, element); } @Override - public boolean retainAll(Collection c) { - throw new UnsupportedOperationException(); + public void add(int index, E element) { + list.add(index, element); + } + + @Override + public E remove(int index) { + return list.remove(index); + } + + @Override + public int indexOf(Object o) { + return list.indexOf(o); } - }); + + @Override + public int lastIndexOf(Object o) { + return list.lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return list.listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return list.listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return list.subList(fromIndex, toIndex); + } + } + assertMatches("truly unmodifiable list", isUnmodifiable(), new CustomUnmodifiableList<>(Arrays.asList(1, 2, 3))); + } + + public void testMatchesUnmodifiableSet() { + assertMatches("truly unmodifiable set", isUnmodifiable(), Collections.unmodifiableSet(Collections.emptySet())); + } + + public void testMatchesUnmodifiableCollection() { + assertMatches("truly unmodifiable collection", isUnmodifiable(), Collections.unmodifiableCollection(Arrays.asList(1, 2, 3))); + } + + public void testMismatchesArrayList() { + assertMismatchDescription("was able to add a value into the list by index", isUnmodifiable(), new ArrayList<>()); + } + + public void testMismatchesArraysList() { + assertMismatchDescription("was able to set an element of the collection", isUnmodifiable(), Arrays.asList(1, 2, 3)); + } + + public void testMismatchesHashSet() { + assertMismatchDescription("was able to add a value into the collection", isUnmodifiable(), new HashSet<>()); + } + + public void testMismatches() { + for (String[] errorCondition : ERROR_CONDITIONS) { + String[] unsupportedMethods = new String[errorCondition.length - 1]; + System.arraycopy(errorCondition, 1, unsupportedMethods, 0, unsupportedMethods.length); + ArrayListWrapper arrayListWrapper = new ArrayListWrapper<>(Arrays.asList(1, 2, 3), unsupportedMethods); + String error = errorCondition[0]; + if (error != null) { + assertMismatchDescription( + error, + isUnmodifiable(), + arrayListWrapper + ); + } else { + assertMatches("truly unmodifiable collection", isUnmodifiable(), arrayListWrapper); + } + } + } + + static class ArrayListWrapper extends ArrayList { + private final Set unsupportedMethods; + + @SuppressWarnings("unused") // Used by reflection + public ArrayListWrapper(Collection c) { + super(c); + if (c instanceof ArrayListWrapper) { + this.unsupportedMethods = new HashSet<>(((ArrayListWrapper) c).unsupportedMethods); + } else { + throw new IllegalStateException(); + } + } + + public ArrayListWrapper(List list, String... unsupportedMethods) { + super(list); + this.unsupportedMethods = new HashSet<>(Arrays.asList(unsupportedMethods)); + } + + @Override + public E set(int index, E element) { + if (unsupportedMethods.contains(SET_INT_INDEX_E_ELEMENT)) throw new UnsupportedOperationException(); + return super.set(index, element); + } + + @Override + public boolean add(E e) { + if (unsupportedMethods.contains(ADD_E_E)) throw new UnsupportedOperationException(); + return super.add(e); + } + + @Override + public void add(int index, E element) { + if (unsupportedMethods.contains(ADD_INT_INDEX_E_ELEMENT)) throw new UnsupportedOperationException(); + super.add(index, element); + } + + @Override + public E remove(int index) { + if (unsupportedMethods.contains(REMOVE_INT_INDEX)) throw new UnsupportedOperationException(); + return super.remove(index); + } + + @Override + public boolean remove(Object o) { + if (unsupportedMethods.contains(REMOVE_OBJECT_O)) throw new UnsupportedOperationException(); + return super.remove(o); + } + + @Override + public void clear() { + if (unsupportedMethods.contains(CLEAR)) throw new UnsupportedOperationException(); + super.clear(); + } + + @Override + public boolean addAll(Collection c) { + if (unsupportedMethods.contains(ADD_ALL_COLLECTION_EXTENDS_E_C)) throw new UnsupportedOperationException(); + return super.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + if (unsupportedMethods.contains(ADD_ALL_INT_INDEX_COLLECTION_EXTENDS_E_C)) + throw new UnsupportedOperationException(); + return super.addAll(index, c); + } + + @Override + public boolean removeAll(Collection c) { + if (unsupportedMethods.contains(REMOVE_ALL_COLLECTION_C)) throw new UnsupportedOperationException(); + return super.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + if (unsupportedMethods.contains(RETAIN_ALL_COLLECTION_C)) throw new UnsupportedOperationException(); + return super.retainAll(c); + } } } From 6266372a84f1bfac9fb103275d81464d7840059b Mon Sep 17 00:00:00 2001 From: andremoniy2 Date: Thu, 17 Feb 2022 14:56:07 +0100 Subject: [PATCH 3/3] Fix for JDK 17+ --- .../hamcrest/collection/IsUnmodifiableCollection.java | 9 +++++++++ .../collection/IsUnmodifiableCollectionTest.java | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java index 72030a5f..5f72ca7f 100644 --- a/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java +++ b/hamcrest/src/main/java/org/hamcrest/collection/IsUnmodifiableCollection.java @@ -15,6 +15,7 @@ public class IsUnmodifiableCollection extends TypeSafeDiagnosingMatcher DEFAULT_COLLECTIONS = new HashMap<>(); private static final Set KNOWN_UNMODIFIABLE_COLLECTIONS = new HashSet<>(); + private static final Set KNOWN_MODIFIABLE_COLLECTIONS = new HashSet<>(); static { final List list = Arrays.asList("a", "b", "c"); @@ -24,6 +25,8 @@ public class IsUnmodifiableCollection extends TypeSafeDiagnosingMatcher