001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.apache.shiro.cdi; 015 016import java.lang.annotation.Annotation; 017import java.util.Set; 018import java.util.stream.Collectors; 019import java.util.stream.Stream; 020import javax.enterprise.inject.spi.AnnotatedType; 021 022import lombok.Getter; 023import lombok.experimental.Delegate; 024 025/** 026 * Wraps annotation types to facilitate additional annotations for CDI 027 * 028 * @param <T> type of annotated class 029 */ 030public class AnnotatedTypeWrapper<T> implements AnnotatedType<T> { 031 // the below is so the compiler doesn't complain about unchecked casts 032 private abstract class AT implements AnnotatedType<T> { 033 } 034 035 private final @Delegate(types = AT.class) AnnotatedType<T> wrapped; 036 private final @Getter Set<Annotation> annotations; 037 038 039 public AnnotatedTypeWrapper(AnnotatedType<T> wrapped, Annotation... additionalAnnotations) { 040 this(wrapped, true, Set.of(additionalAnnotations), Set.of()); 041 } 042 043 044 public AnnotatedTypeWrapper(AnnotatedType<T> wrapped, boolean keepOriginalAnnotations, 045 Set<Annotation> additionalAnnotations, Set<Annotation> annotationsToRemove) { 046 this.wrapped = wrapped; 047 Stream.Builder<Annotation> builder = Stream.builder(); 048 if (keepOriginalAnnotations) { 049 var annotationTypesToExclude = annotationsToRemove.stream() 050 .map(AnnotatedTypeWrapper::checkIfAnnotation) 051 .map(Annotation::annotationType).collect(Collectors.toSet()); 052 wrapped.getAnnotations().stream().filter(ann -> 053 !annotationTypesToExclude.contains(ann.annotationType())) 054 .forEach(builder::add); 055 } 056 additionalAnnotations.forEach(annotation -> addToBuilder(builder, annotation)); 057 annotations = builder.build().collect(Collectors.toSet()); 058 } 059 060 @Override 061 public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) { 062 return annotations.stream().anyMatch(annotationType::isInstance); 063 } 064 065 private void addToBuilder(Stream.Builder<Annotation> builder, Annotation ann) { 066 checkIfAnnotation(ann); 067 builder.add(ann); 068 } 069 070 private static Annotation checkIfAnnotation(Annotation ann) { 071 if (!ann.annotationType().isInstance(ann)) { 072 throw new IllegalArgumentException(ann.getClass().getName()); 073 } 074 return ann; 075 } 076}