This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/isis.git
commit 0ecd43cf7400520fddfeba61ae8249608a0b07dd Author: Andi Huber <ahu...@apache.org> AuthorDate: Thu Apr 12 08:29:19 2018 +0200 ISIS-1932 Internal API _Collections: add 'unmodifiable collectors' --- .../applib/internal/collections/_Collections.java | 192 +++++++++++++++++++++ .../collections/_Collections_Collector.java | 80 +++++++++ .../collections/_Collections_SortedSetOfList.java | 149 ++++++++++++++++ .../MethodIncompatibilityWorkaround.java | 160 +---------------- .../core/metamodel/services/ServicesInjector.java | 15 +- .../core/metamodel/specloader/CollectionUtils.java | 52 ------ 6 files changed, 431 insertions(+), 217 deletions(-) diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections.java b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections.java new file mode 100644 index 0000000..96c59e6 --- /dev/null +++ b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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.apache.isis.applib.internal.collections; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +/** + * <h1>- internal use only -</h1> + * <p> + * Common Collection creation and adapting idioms. + * </p> + * <p> + * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/> + * These may be changed or removed without notice! + * </p> + * + * @since 2.0.0 + */ +public class _Collections { + + // -- COLLECTION UNMODIFIABLE ADAPTERS (FOR LIST) + + /** + * Adapts the {@code list} as unmodifiable collection. + * Same as {@link Collections#unmodifiableCollection(List)}. + * + * @param list + * @return null if {@code list} is null + */ + public static <T> Collection<T> asUnmodifiableCollection(@Nullable final List<T> list) { + if(list==null) { + return null; + } + return Collections.unmodifiableCollection(list); + } + + /** + * Adapts the {@code list} as unmodifiable list. + * Same as {@link Collections#unmodifiableList(List)}. + * + * @param list + * @return + */ + public static <T> List<T> asUnmodifiableList(@Nullable final List<T> list) { + if(list==null) { + return null; + } + return Collections.unmodifiableList(list); + } + + /** + * Preserves order, adapts the {@code list} as Set.<br/><br/> + * + * Any duplicate elements of the list will not be added to the set. + * An element e1 is a duplicate of e2 if {@code e1.equals(e2) == true}. + * + * @param list + * @return null if {@code list} is null + */ + public static <T> Set<T> asUnmodifiableSet(@Nullable final List<T> list) { + if(list==null) { + return null; + } + return Collections.unmodifiableSet( + (Set<T>) + list.stream() + .collect(Collectors.toCollection(LinkedHashSet::new))); + } + + /** + * Preserves order, adapts the {@code list} as SortedSet.<br/><br/> + * + * Any duplicate elements of the list will not be added to the set. + * An element e1 is a duplicate of e2 if {@code e1.equals(e2) == true}. + * + * @param list + * @return null if {@code list} is null + */ + public static <T> SortedSet<T> asUnmodifiableSortedSet(@Nullable final List<T> list) { + if(list==null) { + return null; + } + return _Collections_SortedSetOfList.of(list); + } + + // -- STREAM TO UMODIFIABLE COLLECTION COLLECTORS + + /** + * @return a collector that collects elements of a stream into an unmodifiable List + */ + public static <T> Collector<T, List<T>, List<T>> toUnmodifiableList() { + return new _Collections_Collector<>(ArrayList::new, Collections::unmodifiableList); + } + + /** + * @return a collector that collects elements of a stream into an unmodifiable Set + */ + public static <T> Collector<T, Set<T>, Set<T>> toUnmodifiableSet() { + return new _Collections_Collector<>(HashSet::new, Collections::unmodifiableSet); + } + + /** + * @return a collector that collects elements of a stream into an unmodifiable SortedSet + */ + public static <T> Collector<T, SortedSet<T>, SortedSet<T>> toUnmodifiableSortedSet() { + return new _Collections_Collector<>(TreeSet::new, Collections::unmodifiableSortedSet); + } + + /** + * @return a collector that collects elements of a stream into an unmodifiable Collection + */ + public static <T> Collector<T, Collection<T>, Collection<T>> toUnmodifiableCollection() { + return new _Collections_Collector<>(ArrayList::new, Collections::unmodifiableCollection); + } + + /** + * @return a collector that collects elements of a stream into an unmodifiable SortedSet + */ + public static <T> Collector<T, SortedSet<T>, SortedSet<T>> toUnmodifiableSortedSet( + @Nullable Comparator<T> comparator) { + + if(comparator==null) { + return toUnmodifiableSortedSet(); + } + return new _Collections_Collector<>(()->new TreeSet<>(comparator), Collections::unmodifiableSortedSet); + } + + /** + * @return a collector that collects elements of a stream into an unmodifiable + * List, Set, SortedSet or Collection. + * @throws IllegalArgumentException if the {@link typeOfCollection} is not one of + * List, Set, SortedSet or Collection. + */ + public static <T> Collector<T, ?, ? extends Collection<T>> toUnmodifiableOfType(Class<?> typeOfCollection) { + + Objects.requireNonNull(typeOfCollection); + + if(SortedSet.class.equals(typeOfCollection)) { + return toUnmodifiableSortedSet(); + } + + if(Set.class.equals(typeOfCollection)) { + return toUnmodifiableSet(); + } + + if(List.class.equals(typeOfCollection)) { + return toUnmodifiableList(); + } + + if(Collection.class.equals(typeOfCollection)) { + return toUnmodifiableCollection(); + } + + throw new IllegalArgumentException( + String.format("Can not collect into %s. Only List, Set, SortedSet and Collection are supported.", + typeOfCollection.getClass().getName())); + } + + // -- + +} diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_Collector.java b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_Collector.java new file mode 100644 index 0000000..10a8b7a --- /dev/null +++ b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_Collector.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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.apache.isis.applib.internal.collections; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +/** + * + * package private mixin for utility class {@link _Collections} + * + * Collector for Collections. + * + */ +class _Collections_Collector<T, C extends Collection<T>> implements Collector<T, C, C> { + + private final Supplier<C> supplier; + private final Function<C, C> finisher; + + _Collections_Collector(Supplier<C> supplier, Function<C, C> finisher) { + this.supplier = Objects.requireNonNull(supplier); + this.finisher = Objects.requireNonNull(finisher); + } + + @Override + public Supplier<C> supplier() { + return supplier; + } + + @Override + public BiConsumer<C, T> accumulator() { + return Collection::add; + } + + @Override + public BinaryOperator<C> combiner() { + return (left, right) -> { left.addAll(right); return left; }; + } + + @Override + public Function<C, C> finisher() { + return finisher; + } + + @Override + public Set<Characteristics> characteristics() { + return Collections.emptySet(); + } + + +} + + + + + diff --git a/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_SortedSetOfList.java b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_SortedSetOfList.java new file mode 100644 index 0000000..add7d8a --- /dev/null +++ b/core/applib/src/main/java/org/apache/isis/applib/internal/collections/_Collections_SortedSetOfList.java @@ -0,0 +1,149 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 + * + * http://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.apache.isis.applib.internal.collections; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.SortedSet; + +/** + * + * package private mixin for utility class {@link _Collections} + * + */ +class _Collections_SortedSetOfList<T> implements SortedSet<T> { + + private final static String JUST_AN_ADAPTER = + "this set is just an adapter, it has no information about the intended comparator"; + + static <T> _Collections_SortedSetOfList<T> of(List<T> list){ + return new _Collections_SortedSetOfList<>(list); + } + + private final List<T> list; + + private _Collections_SortedSetOfList(List<T> list) { + this.list = list; + } + + @Override + public int size() { + return list.size(); + } + + @Override + public boolean isEmpty() { + return list.isEmpty(); + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public Iterator<T> iterator() { + return list.iterator(); + } + + @Override + public Object[] toArray() { + return list.toArray(); + } + + @Override + public <X> X[] toArray(X[] a) { + return list.toArray(a); + } + + @Override + public boolean add(T e) { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public boolean containsAll(Collection<?> c) { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public boolean addAll(Collection<? extends T> c) { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public boolean retainAll(Collection<?> c) { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public boolean removeAll(Collection<?> c) { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("unmodifiable"); + } + + @Override + public Comparator<? super T> comparator() { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public SortedSet<T> subSet(T fromElement, T toElement) { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public SortedSet<T> headSet(T toElement) { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public SortedSet<T> tailSet(T fromElement) { + throw new UnsupportedOperationException(JUST_AN_ADAPTER); + } + + @Override + public T first() { + if(size()==0) { + throw new NoSuchElementException("set is empty"); + } + return list.get(0); + } + + @Override + public T last() { + if(size()==0) { + throw new NoSuchElementException("set is empty"); + } + return list.get(size()-1); + } +} diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/MethodIncompatibilityWorkaround.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/MethodIncompatibilityWorkaround.java index e8a2920..46000b4 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/MethodIncompatibilityWorkaround.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/MethodIncompatibilityWorkaround.java @@ -22,17 +22,12 @@ package org.apache.isis.core.metamodel.facets.actions.action.invocation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.LinkedHashSet; import java.util.List; -import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedSet; -import java.util.stream.Collectors; import org.apache.isis.applib.internal.base._NullSafe; +import org.apache.isis.applib.internal.collections._Collections; /** * Package private utility for method invocation pre-processing. @@ -75,171 +70,26 @@ class MethodIncompatibilityWorkaround { // allow no side effects on Collection arguments if(Collection.class.equals(parameterType)) { - return adaptAsCollection((List<?>)obj); + return _Collections.asUnmodifiableCollection((List<?>)obj); } // allow no side effects on List arguments if(List.class.equals(parameterType)) { - return adaptAsList((List<?>)obj); + return _Collections.asUnmodifiableList((List<?>)obj); } // adapt as Set (unmodifiable) if(Set.class.equals(parameterType)) { - return adaptAsSet((List<?>)obj); + return _Collections.asUnmodifiableSet((List<?>)obj); } // adapt as SortedSet (unmodifiable) if(SortedSet.class.equals(parameterType)) { - return adaptAsSortedSet((List<?>)obj); + return _Collections.asUnmodifiableSortedSet((List<?>)obj); } return obj; } - // -- COLLECTION ADAPTERS - - /** - * Adapts the list as unmodifiable collection. - * @param list - * @return - */ - private static <T> Collection<T> adaptAsCollection(final List<T> list) { - return Collections.unmodifiableCollection(list); - } - - /** - * Adapts the list as unmodifiable list. - * @param list - * @return - */ - private static <T> List<T> adaptAsList(final List<T> list) { - return Collections.unmodifiableList(list); - } - - /** - * Preserves order, adapts the Set interface. - * @param list - * @return - */ - private static <T> Set<T> adaptAsSet(final List<T> list) { - return Collections.unmodifiableSet( - (Set<T>) - list.stream() - .collect(Collectors.toCollection(LinkedHashSet::new))); - } - - private final static String JUST_AN_ADAPTER = - "this set is just an adapter, it has no information about the intended comparator"; - - /** - * Preserves order, adapts the SortedSet interface. - * @param list - * @return - */ - private static <T> SortedSet<T> adaptAsSortedSet(final List<T> list) { - return new SortedSet<T>() { - - @Override - public int size() { - return list.size(); - } - - @Override - public boolean isEmpty() { - return list.isEmpty(); - } - - @Override - public boolean contains(Object o) { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public Iterator<T> iterator() { - return list.iterator(); - } - - @Override - public Object[] toArray() { - return list.toArray(); - } - - @Override - public <X> X[] toArray(X[] a) { - return list.toArray(a); - } - - @Override - public boolean add(T e) { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public boolean remove(Object o) { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public boolean containsAll(Collection<?> c) { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public boolean addAll(Collection<? extends T> c) { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public boolean retainAll(Collection<?> c) { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public boolean removeAll(Collection<?> c) { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public void clear() { - throw new UnsupportedOperationException("unmodifiable"); - } - - @Override - public Comparator<? super T> comparator() { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public SortedSet<T> subSet(T fromElement, T toElement) { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public SortedSet<T> headSet(T toElement) { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public SortedSet<T> tailSet(T fromElement) { - throw new UnsupportedOperationException(JUST_AN_ADAPTER); - } - - @Override - public T first() { - if(size()==0) { - throw new NoSuchElementException("set is empty"); - } - return list.get(0); - } - - @Override - public T last() { - if(size()==0) { - throw new NoSuchElementException("set is empty"); - } - return list.get(size()-1); - } - }; - } } diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java index b9d9773..3f52cb4 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/ServicesInjector.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; import org.apache.isis.applib.annotation.Programmatic; import org.apache.isis.applib.internal.base._NullSafe; +import org.apache.isis.applib.internal.collections._Collections; import org.apache.isis.applib.internal.collections._Lists; import org.apache.isis.applib.internal.collections._Maps; import org.apache.isis.applib.internal.collections._Multimaps; @@ -290,16 +291,10 @@ public class ServicesInjector implements ApplicationScopedComponent { final Class<? extends Collection<Object>> collectionTypeToBeInjected = (Class<? extends Collection<Object>>) typeToBeInjected; - final Collection<Object> collectionOfServices = - CollectionUtils.collectIntoUnmodifiableCompatibleWithCollectionType( - - collectionTypeToBeInjected, - - _NullSafe.stream(services) - .filter(_NullSafe::isPresent) - .filter(isOfType(elementType)) - - ); + final Collection<Object> collectionOfServices = _NullSafe.stream(services) + .filter(_NullSafe::isPresent) + .filter(isOfType(elementType)) + .collect(_Collections.toUnmodifiableOfType(collectionTypeToBeInjected)); invokeInjectorField(field, object, collectionOfServices); }); diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/CollectionUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/CollectionUtils.java index 7d8fe7b..80a35a0 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/CollectionUtils.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/CollectionUtils.java @@ -22,17 +22,7 @@ package org.apache.isis.core.metamodel.specloader; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.function.Consumer; -import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.annotation.Nullable; @@ -142,47 +132,5 @@ public final class CollectionUtils { } } - - // -- COLLECT ELEMENTS FROM STREAM - - /** - * Collects elements from stream into a collection that is compatible with the given typeOfCollection. - * @param typeOfCollection - * @param elementStream - * @return - * - * @throws IllegalArgumentException if the given typeOfCollection is not supported - */ - public static <T> Collection<T> collectIntoUnmodifiableCompatibleWithCollectionType ( - Class<?> typeOfCollection, Stream<? extends T> elementStream) { - - if(SortedSet.class.equals(typeOfCollection)) { - return Collections.unmodifiableSortedSet( - elementStream.collect(Collectors.<T, SortedSet<T>>toCollection(TreeSet::new)) - ); - } - - if(Set.class.equals(typeOfCollection)) { - return Collections.unmodifiableSet( - elementStream.collect(Collectors.<T, Set<T>>toCollection(HashSet::new)) - ); - } - - if(List.class.equals(typeOfCollection)) { - return Collections.unmodifiableList( - elementStream.collect(Collectors.<T, List<T>>toCollection(ArrayList::new)) - ); - } - - if(Collection.class.equals(typeOfCollection)) { - return Collections.unmodifiableCollection( - elementStream.collect(Collectors.toCollection(ArrayList::new)) - ); - } - - throw new IllegalArgumentException( - String.format("Can not collect into %s. Only List, Set, SortedSet and Collection are supported.", - typeOfCollection.getClass().getName())); - } } -- To stop receiving notification emails like this one, please contact ahu...@apache.org.