001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*- 002 * 003 * Copyright © 2024–2026 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.util.Collection; 017import java.util.List; 018 019import javax.lang.model.AnnotatedConstruct; 020 021import javax.lang.model.element.AnnotationMirror; 022import javax.lang.model.element.Element; 023 024import javax.lang.model.type.ArrayType; 025import javax.lang.model.type.DeclaredType; 026import javax.lang.model.type.TypeMirror; 027import javax.lang.model.type.TypeVariable; 028 029import org.microbean.assign.Annotated; 030import org.microbean.assign.Matcher; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * A {@link Matcher} that tests an {@link Id} to see if it <dfn>matches</dfn> an {@link AnnotatedConstruct}. 036 * 037 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 038 * 039 * @see #test(Annotated, Id) 040 * 041 * @see BeanQualifiersMatcher 042 * 043 * @see BeanTypeMatcher 044 * 045 * @see Matcher 046 * 047 * @see Id 048 * 049 * @see Beans#typesafeFilteringSelectable(Collection, Matcher) 050 */ 051// Convenience. Nothing actually refers to this class. See Selectables#typesafeFiltering(Collection, Matcher) 052public final class IdMatcher implements Matcher<Annotated<? extends AnnotatedConstruct>, Id> { 053 054 private final BeanTypeMatcher tm; 055 056 private final BeanQualifiersMatcher qm; 057 058 private final Matcher<? super Annotated<? extends AnnotatedConstruct>, ? super Id> other; 059 060 /** 061 * Creates a new {@link IdMatcher}. 062 * 063 * @param tm a {@link BeanTypeMatcher}; must not be {@code null} 064 * 065 * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} 066 * 067 * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} 068 * 069 * @see #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, Matcher) 070 */ 071 public IdMatcher(final BeanTypeMatcher tm, final BeanQualifiersMatcher qm) { 072 this(tm, qm, null); 073 } 074 075 /** 076 * Creates a new {@link IdMatcher}. 077 * 078 * @param tm a {@link BeanTypeMatcher}; must not be {@code null} 079 * 080 * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} 081 * 082 * @param other a supplementary {@link Matcher}; may be {@code null} 083 * 084 * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} 085 */ 086 public IdMatcher(final BeanTypeMatcher tm, 087 final BeanQualifiersMatcher qm, 088 final Matcher<? super Annotated<? extends AnnotatedConstruct>, ? super Id> other) { 089 super(); 090 this.tm = requireNonNull(tm, "tm"); 091 this.qm = requireNonNull(qm, "qm"); 092 this.other = other == null ? (ac, id) -> true : other; 093 } 094 095 /* 096 * Tests the supplied {@link Id} to see if it <dfn>matches</dfn> the supplied {@link AnnotatedConstruct} and returns the 097 * result. 098 * 099 * @param ac an {@link AnnotatedConstruct}; must not be {@code null} 100 * 101 * @param id an {@link Id}; must not be {@code null} 102 * 103 * @return {@code true} if {@code id} matches {@code ac}; {@code false} otherwise 104 * 105 * @exception NullPointerException if any argument is {@code null} 106 * 107 * @see #test(Annotated, Id) 108 * 109 * @see Annotated#of(AnnotatedConstruct, Predicate) 110 * 111 * @see BeanQualifiersMatcher#test(Collection, Collection) 112 * 113 * @see #test(TypeMirror, Iterable) 114 * 115 * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) 116 */ 117 // @Deprecated(forRemoval = true) // Annotated.of(AnnotatedConstruct) exists 118 // public final boolean test(final AnnotatedConstruct ac, final Id id) { 119 // return this.test(Annotated.of(ac, this.qm.annotationElementInclusionPredicate()), id); 120 // } 121 122 /** 123 * Tests the supplied {@link Id} to see if it <dfn>matches</dfn> the supplied {@link Annotated Annotated<? extends 124 * AnnotatedConstruct>} and returns the result. 125 * 126 * @param aac an {@link Annotated Annotated<? extends AnnotatedConstruct>}; must not be {@code null} 127 * 128 * @param id an {@link Id}; must not be {@code null} 129 * 130 * @return {@code true} if {@code id} matches {@code aac}; {@code false} otherwise 131 * 132 * @exception NullPointerException if any argument is {@code null} 133 * 134 * @see Annotated#of(AnnotatedConstruct, Predicate) 135 * 136 * @see BeanQualifiersMatcher#test(Collection, Collection) 137 * 138 * @see #test(TypeMirror, Iterable) 139 * 140 * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) 141 */ 142 @Override // Matcher<Annotated<? extends AnnotatedConstruct>, Id> 143 public final boolean test(final Annotated<? extends AnnotatedConstruct> aac, final Id id) { 144 final AnnotatedConstruct ac = aac.annotated(); 145 return 146 this.test(ac instanceof Element e ? e.asType() : (TypeMirror)ac, id.types()) && 147 this.qm.test(aac.annotations(), id.annotations()) && 148 this.other.test(aac, id); 149 } 150 151 /** 152 * Tests the supplied {@link Iterable} of {@link TypeMirror}s to see if at least one {@link TypeMirror} it yields 153 * <dfn>matches</dfn> the supplied {@link TypeMirror} and returns the result. 154 * 155 * <p>A {@link TypeMirror} <em>t</em> from the supplied {@link Iterable} <dfn>matches</dfn> the supplied {@code type} 156 * argument if an invocation of the {@link BeanTypeMatcher#test(TypeMirror, TypeMirror)} method invoked on the 157 * {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, InterceptorBindingsMatcher) 158 * <code>BeanTypeManager</code> supplied at construction time} supplied with {@code type} and <em>t</em> returns 159 * {@code true}.</p> 160 * 161 * @param type a {@link TypeMirror} to test against; must not be {@code null} 162 * 163 * @param candidatess an {@link Iterable} of {@link TypeMirror}s; must not be {@code null} 164 * 165 * @return {@code true} if at least one {@link TypeMirror} from {@code candidates} matches {@code type} 166 * 167 * @exception NullPointerException if any argument is {@code null} 168 * 169 * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) 170 */ 171 private final boolean test(final TypeMirror type, final Iterable<? extends TypeMirror> candidates) { 172 requireNonNull(type, "type"); 173 for (final TypeMirror candidate : candidates) { 174 if (this.tm.test(type, candidate)) { 175 return true; 176 } 177 } 178 return false; 179 } 180 181}