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