001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.util;
021
022import jakarta.annotation.Nonnull;
023import jakarta.annotation.Nullable;
024import org.apache.commons.collections4.CollectionUtils;
025
026import java.util.Collection;
027import java.util.Collections;
028import java.util.HashSet;
029import java.util.Set;
030
031import static java.util.Collections.unmodifiableCollection;
032
033public class CollectionUtil {
034
035        /**
036         * Non instantiable
037         */
038        private CollectionUtil() {
039                // nothing
040        }
041
042        /**
043         * Returns an immutable union of both collections. If either or both arguments are
044         * <code>null</code> they will be treated as an empty collection, meaning
045         * that even if both arguments are <code>null</code>, an empty immutable
046         * collection will be returned.
047         * <p>
048         * DO NOT use this method if the underlying collections can be changed
049         * after calling this method, as the behaviour is indeterminate.
050         * </p>
051         *
052         * @param theCollection0 The first set in the union, or <code>null</code>.
053         * @param theCollection1 The second set in the union, or <code>null</code>.
054         * @return Returns a union of both collections. Will not return <code>null</code> ever.
055         * @since 7.4.0
056         */
057        @Nonnull
058        public static <T> Collection<T> nullSafeUnion(
059                        @Nullable Collection<T> theCollection0, @Nullable Collection<T> theCollection1) {
060                Collection<T> collection0 = theCollection0;
061                if (collection0 != null && collection0.isEmpty()) {
062                        collection0 = null;
063                }
064                Collection<T> collection1 = theCollection1;
065                if (collection1 != null && collection1.isEmpty()) {
066                        collection1 = null;
067                }
068                if (collection0 == null && collection1 == null) {
069                        return Collections.emptySet();
070                }
071                if (collection0 == null) {
072                        return unmodifiableCollection(collection1);
073                }
074                if (collection1 == null) {
075                        return unmodifiableCollection(collection0);
076                }
077                return CollectionUtils.union(collection0, collection1);
078        }
079
080        /**
081         * This method is equivalent to <code>Set.of(...)</code> but is kept here
082         * and used instead of that method because Set.of is not present on Android
083         * SDKs (at least up to 29).
084         * <p>
085         * Sets returned by this method are unmodifiable.
086         * </p>
087         */
088        @SuppressWarnings("unchecked")
089        public static <T> Set<T> newSet(T... theValues) {
090                HashSet<T> retVal = new HashSet<>();
091                Collections.addAll(retVal, theValues);
092                return Collections.unmodifiableSet(retVal);
093        }
094}