001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 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.assign; 015 016import java.util.Collection; 017import java.util.SequencedSet; 018 019import java.util.function.Function; 020 021import static java.util.Collections.unmodifiableSequencedSet; 022 023import static java.util.LinkedHashSet.newLinkedHashSet; 024 025/** 026 * An object with {@linkplain AttributedElement dependencies}. 027 * 028 * <p>By default, {@link Aggregate}s have {@linkplain #EMPTY_DEPENDENCIES no dependencies}.</p> 029 * 030 * @author <a href="https://about.me/lairdnelson/" target="_top">Laird Nelson</a> 031 * 032 * @see #dependencies() 033 */ 034public interface Aggregate { 035 036 037 /* 038 * Static fields. 039 */ 040 041 042 /** 043 * An immutable, empty {@link SequencedSet} of {@link Assignment}s. 044 */ 045 public static final SequencedSet<Assignment<?>> EMPTY_ASSIGNMENTS = unmodifiableSequencedSet(newLinkedHashSet(0)); 046 047 /** 048 * An immutable, empty {@link SequencedSet} of {@link AttributedElement}s. 049 */ 050 public static final SequencedSet<AttributedElement> EMPTY_DEPENDENCIES = unmodifiableSequencedSet(newLinkedHashSet(0)); 051 052 053 /* 054 * Default instance methods. 055 */ 056 057 058 /** 059 * Returns an immutable, determinate, {@link SequencedSet} of {@link AttributedElement} instances. 060 * 061 * <p>If an {@link AttributedElement} in the set returns a {@link javax.lang.model.element.TypeElement} from its 062 * {@link AttributedElement#element()} method that represents this {@link Aggregate} implementation, undefined 063 * behavior, including the possibility of infinite loops, may result (an {@link Aggregate} may not have itself as a 064 * dependency).</p> 065 * 066 * <p>Note that it is permissible for an {@link AttributedElement} in the set to refer to another type by returning a 067 * {@link javax.lang.model.element.TypeElement} from its {@link AttributedElement#element()} method.</p> 068 * 069 * <p>The default implementation of this method returns the value of the {@link #EMPTY_DEPENDENCIES} field.</p> 070 * 071 * @return an immutable, determinate, {@link SequencedSet} of {@link AttributedElement} instances; never {@code null} 072 * 073 * @see AttributedElement 074 */ 075 public default SequencedSet<AttributedElement> dependencies() { 076 return EMPTY_DEPENDENCIES; 077 } 078 079 /** 080 * A convenience method that assigns a contextual reference to each of this {@link Aggregate}'s {@link 081 * AttributedElement} instances and returns the resulting {@link SequencedSet} of {@link Assignment}s. 082 * 083 * <p><strong>Note:</strong> Undefined behavior may result if an {@link AttributedElement} in the {@linkplain 084 * #dependencies() dependencies} represents this {@link Aggregate} implementation (an {@link Aggregate} may not have 085 * itself as a dependency).</p> 086 * 087 * <p>Typically there is no need to override this method.</p> 088 * 089 * <p>Usage of this method is not required.</p> 090 * 091 * @param r a {@link Function} that retrieves a contextual reference suitable for an {@link AttributedType}; if {@link 092 * #dependencies()} returns a non-empty {@link SequencedSet} then this argument must not be {@code null} 093 * 094 * @return an immutable {@link SequencedSet} of {@link Assignment} instances; never {@code null} 095 * 096 * @exception NullPointerException if {@code r} is {@code null} 097 */ 098 // (Convenience.) 099 public default SequencedSet<? extends Assignment<?>> assign(final Function<? super AttributedType, ?> r) { 100 final Collection<? extends AttributedElement> ds = this.dependencies(); 101 if (ds == null || ds.isEmpty()) { 102 return EMPTY_ASSIGNMENTS; 103 } 104 final SequencedSet<Assignment<?>> assignments = newLinkedHashSet(ds.size()); 105 ds.forEach(d -> assignments.add(new Assignment<>(d, r.apply(d.attributedType())))); 106 return unmodifiableSequencedSet(assignments); 107 } 108 109}