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.util.Collection; 017import java.util.Objects; 018 019import javax.lang.model.type.TypeMirror; 020 021import org.microbean.assign.AttributedType; 022import org.microbean.assign.Matcher; 023 024import org.microbean.attributes.Attributes; 025 026/** 027 * A {@link Matcher} that tests an {@link Id} to see if it matches an {@link AttributedType}. 028 * 029 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 030 * 031 * @see #test(AttributedType, Id) 032 * 033 * @see BeanQualifiersMatcher 034 * 035 * @see BeanTypeMatcher 036 * 037 * @see Matcher 038 * 039 * @see Id 040 */ 041public final class IdMatcher implements Matcher<AttributedType, Id> { 042 043 private final BeanTypeMatcher tm; 044 045 private final BeanQualifiersMatcher qm; 046 047 private final Matcher<AttributedType, Id> other; 048 049 /** 050 * Creates a new {@link IdMatcher}. 051 * 052 * @param tm a {@link BeanTypeMatcher}; must not be {@code null} 053 * 054 * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} 055 * 056 * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} 057 * 058 * @see #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, Matcher) 059 */ 060 public IdMatcher(final BeanTypeMatcher tm, final BeanQualifiersMatcher qm) { 061 this(tm, qm, null); 062 } 063 064 /** 065 * Creates a new {@link IdMatcher}. 066 * 067 * @param tm a {@link BeanTypeMatcher}; must not be {@code null} 068 * 069 * @param qm a {@link BeanQualifiersMatcher}; must not be {@code null} 070 * 071 * @param other a supplementary {@link Matcher}; may be {@code null} 072 * 073 * @exception NullPointerException} if {@code tm} or {@code qm} is {@code null} 074 */ 075 public IdMatcher(final BeanTypeMatcher tm, 076 final BeanQualifiersMatcher qm, 077 final Matcher<AttributedType, Id> other) { 078 super(); 079 this.tm = Objects.requireNonNull(tm, "tm"); 080 this.qm = Objects.requireNonNull(qm, "qm"); 081 this.other = other == null ? (t, i) -> true : other; 082 } 083 084 /** 085 * Tests the supplied {@link Id} to see if it <dfn>matches</dfn> the supplied {@link AttributedType} and returns the 086 * result. 087 * 088 * <p>An {@link Id} <dfn>matches</dfn> an {@link AttributedType} if and only if all of the following are {@code 089 * true}:</p> 090 * 091 * <ol> 092 * 093 * <li>An invocation of the {@link BeanQualifiersMatcher#test(Collection, Collection)} method on the {@link 094 * BeanQualifiersMatcher} supplied at {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, 095 * Matcher) construction time} supplied with the supplied {@linkplain AttributedType#attributes() 096 * <code>AttributedType</code>'s attributes} and the supplied {@linkplain Id#attributes() <code>Id</code>'s 097 * attributes} returns {@code true}</li> 098 * 099 * <li>An invocation of the {@link Matcher#test(Object, Object)} method on the supplementary {@link Matcher} supplied 100 * at {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, Matcher) construction time} supplied with the 101 * supplied {@linkplain AttributedType} and the supplied {@link Id} returns {@code true}</li> 102 * 103 * <li>An invocation of this {@link IdMatcher}'s {@link #test(TypeMirror, Iterable)} method supplied with the supplied 104 * {@linkplain AttributedType#type() <code>AttributedType</code>'s type} and the supplied {@linkplain Id#attributes() 105 * <code>Id</code>'s attributes} returns {@code true}</li> 106 * 107 * </ol> 108 * 109 * @param t an {@link AttributedType}; must not be {@code null} 110 * 111 * @param id an {@link Id}; must not be {@code null} 112 * 113 * @return {@code true} if {@code id} matches {@code t}; {@code false} otherwise 114 * 115 * @exception NullPointerException if any argument is {@code null} 116 * 117 * @see BeanQualifiersMatcher#test(Collection, Collection) 118 * 119 * @see #test(TypeMirror, Iterable) 120 * 121 * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) 122 */ 123 @Override // Matcher<AttributedType, Id> (BiPredicate<AttributedType, Id>) 124 public final boolean test(final AttributedType t, final Id id) { 125 return 126 this.test(t.type(), id.types()) && 127 this.qm.test(t.attributes(), id.attributes()) && 128 this.other.test(t, id); 129 } 130 131 /** 132 * Tests the supplied {@link Iterable} of {@link TypeMirror}s to see if at least one {@link TypeMirror} it yields 133 * <dfn>matches</dfn> the supplied {@link TypeMirror} and returns the result. 134 * 135 * <p>A {@link TypeMirror} <em>t</em> from the supplied {@link Iterable} <dfn>matches</dfn> the supplied {@code type} 136 * argument if an invocation of the {@link BeanTypeMatcher#test(TypeMirror, TypeMirror)} method invoked on the 137 * {@linkplain #IdMatcher(BeanTypeMatcher, BeanQualifiersMatcher, InterceptorBindingsMatcher) 138 * <code>BeanTypeManager</code> supplied at construction time} supplied with {@code type} and <em>t</em> returns 139 * {@code true}.</p> 140 * 141 * @param type a {@link TypeMirror} to test against; must not be {@code null} 142 * 143 * @param ts an {@link Iterable} of {@link TypeMirror}s; must not be {@code null} 144 * 145 * @return {@code true} if at least one {@link TypeMirror} from {@code ts} matches {@code t} 146 * 147 * @exception NullPointerException if any argument is {@code null} 148 * 149 * @see BeanTypeMatcher#test(TypeMirror, TypeMirror) 150 */ 151 private final boolean test(final TypeMirror type, final Iterable<? extends TypeMirror> ts) { 152 Objects.requireNonNull(type, "type"); 153 for (final TypeMirror t : ts) { 154 if (this.tm.test(type, t)) { 155 return true; 156 } 157 } 158 return false; 159 } 160 161}