001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2024–2025 microBean™. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 011 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 012 * specific language governing permissions and limitations under the License. 013 */ 014package org.microbean.bean; 015 016import java.lang.System.Logger; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Comparator; 021import java.util.List; 022import java.util.Set; 023 024import static java.lang.System.getLogger; 025import static java.util.Collections.sort; 026import static java.util.HashSet.newHashSet; 027 028/** 029 * Utility methods for working with {@link Bean}s. 030 * 031 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 032 * 033 * @see #normalize(Collection) 034 * 035 * @see Bean 036 */ 037public final class Beans { 038 039 040 /* 041 * Static fields. 042 */ 043 044 045 private static final Logger LOGGER = getLogger(Beans.class.getName()); 046 047 private static final Comparator<Bean<?>> byRankComparator = Comparator 048 .<Bean<?>>comparingInt(Ranked::rank) 049 .reversed(); 050 051 private static final Comparator<Bean<?>> byAlternateThenByRankComparator = Comparator 052 .<Bean<?>, Boolean>comparing(Ranked::alternate) 053 .reversed() 054 .thenComparing(byRankComparator); 055 056 057 /* 058 * Constructors. 059 */ 060 061 062 private Beans() { 063 super(); 064 } 065 066 067 /* 068 * Static methods. 069 */ 070 071 072 /** 073 * Returns an immutable {@link List} containing a subset of {@linkplain Bean#equals(Object) distinct elements} 074 * contained in the supplied {@link Collection}, sorted in a deliberately unspecified fashion. 075 * 076 * @param beans a {@link Collection} of {@link Bean}s; must not be {@code null} 077 * 078 * @return a non-{@code null} immutable {@link List} 079 * 080 * @exception NullPointerException if {@code beans} is {@code null} 081 * 082 * @see Bean#equals(Object) 083 */ 084 public static List<Bean<?>> normalize(final Collection<? extends Bean<?>> beans) { 085 if (beans.isEmpty()) { 086 return List.of(); 087 } else if (beans.size() == 1) { 088 // no duplicate weeding or sorting needed 089 return List.copyOf(beans); 090 } 091 final ArrayList<Bean<?>> newBeans = new ArrayList<>(beans.size()); 092 if (beans instanceof Set) { 093 newBeans.addAll(beans); 094 } else { 095 final Set<Bean<?>> newBeansSet = newHashSet(beans.size()); 096 for (final Bean<?> bean : beans) { 097 if (newBeansSet.add(bean)) { 098 newBeans.add(bean); 099 } 100 } 101 if (newBeans.isEmpty()) { 102 return List.of(); 103 } 104 } 105 assert !newBeans.isEmpty(); 106 if (newBeans.size() > 1) { 107 // Sort 108 sort(newBeans, byAlternateThenByRankComparator); 109 } 110 return List.copyOf(newBeans); 111 } 112 113}