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.producer; 015 016import java.util.Collection; 017import java.util.List; 018 019import javax.lang.model.AnnotatedConstruct; 020 021import javax.lang.model.element.AnnotationMirror; 022 023import org.microbean.assign.Annotated; 024import org.microbean.assign.Matcher; 025 026import org.microbean.bean.Id; 027 028import static java.util.Objects.requireNonNull; 029 030import static org.microbean.construct.element.AnnotationMirrors.containsAll; 031import static org.microbean.construct.element.AnnotationMirrors.sameAnnotation; 032 033/** 034 * A {@link Matcher} encapsulating <a 035 * href="https://jakarta.ee/specifications/cdi/4.0/jakarta-cdi-spec-4.0#interceptors">CDI-compatible interceptor binding 036 * matching rules</a>. 037 * 038 * @author <a href="https://about.me/lairdnelson" target="_top">Laird Nelson</a> 039 * 040 * @see #test(Collection, Collection) 041 */ 042// TODO: Now that interceptors have been effectively refactored out into microbean-producer, this might be able to move 043// there, or some other microbean-producer-dependent project. 044public class InterceptorBindingsMatcher implements Matcher<Annotated<? extends AnnotatedConstruct>, Id> { 045 046 private final InterceptorBindings ib; 047 048 /** 049 * Creates a new {@link InterceptorBindingsMatcher}. 050 * 051 * @param ib a non-{@code null} {@link InterceptorBindings} 052 * 053 * @exception NullPointerException if {@code ib} is {@code null} 054 */ 055 public InterceptorBindingsMatcher(final InterceptorBindings ib) { 056 super(); 057 this.ib = requireNonNull(ib, "ib"); 058 } 059 060 private final boolean test(final Collection<? extends AnnotationMirror> receiverAttributes, 061 final Collection<? extends AnnotationMirror> payloadAttributes) { 062 final Collection<? extends AnnotationMirror> payloadBindings = this.ib.interceptorBindings(payloadAttributes); 063 if (payloadBindings.isEmpty()) { 064 return this.ib.interceptorBindings(receiverAttributes).isEmpty(); 065 } else if (payloadBindings.size() == 1 && this.ib.anyInterceptorBinding(payloadBindings.iterator().next())) { 066 return true; 067 } 068 final Collection<? extends AnnotationMirror> receiverBindings = this.ib.interceptorBindings(receiverAttributes); 069 return 070 receiverBindings.size() == payloadBindings.size() && 071 containsAll(receiverBindings, payloadBindings) && 072 containsAll(payloadBindings, receiverBindings); 073 } 074 075 @Override // Matcher<Annotated<? extends AnnotatedConstruct>, Id> 076 public final boolean test(final Annotated<? extends AnnotatedConstruct> aac, final Id id) { 077 return this.test(aac.annotations(), id.annotations()); 078 } 079 080}