001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.context.annotation; 018 019import java.lang.annotation.Annotation; 020 021import org.springframework.core.GenericTypeResolver; 022import org.springframework.core.annotation.AnnotationAttributes; 023import org.springframework.core.type.AnnotationMetadata; 024 025/** 026 * Convenient base class for {@link ImportSelector} implementations that select imports 027 * based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*} 028 * annotations). 029 * 030 * @author Chris Beams 031 * @since 3.1 032 * @param <A> annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute} 033 */ 034public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector { 035 036 /** 037 * The default advice mode attribute name. 038 */ 039 public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode"; 040 041 042 /** 043 * The name of the {@link AdviceMode} attribute for the annotation specified by the 044 * generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME}, 045 * but subclasses may override in order to customize. 046 */ 047 protected String getAdviceModeAttributeName() { 048 return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME; 049 } 050 051 /** 052 * This implementation resolves the type of annotation from generic metadata and 053 * validates that (a) the annotation is in fact present on the importing 054 * {@code @Configuration} class and (b) that the given annotation has an 055 * {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type 056 * {@link AdviceMode}. 057 * <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the 058 * concrete implementation to choose imports in a safe and convenient fashion. 059 * @throws IllegalArgumentException if expected annotation {@code A} is not present 060 * on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)} 061 * returns {@code null} 062 */ 063 @Override 064 public final String[] selectImports(AnnotationMetadata importingClassMetadata) { 065 Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); 066 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); 067 if (attributes == null) { 068 throw new IllegalArgumentException(String.format( 069 "@%s is not present on importing class '%s' as expected", 070 annType.getSimpleName(), importingClassMetadata.getClassName())); 071 } 072 073 AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName()); 074 String[] imports = selectImports(adviceMode); 075 if (imports == null) { 076 throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode); 077 } 078 return imports; 079 } 080 081 /** 082 * Determine which classes should be imported based on the given {@code AdviceMode}. 083 * <p>Returning {@code null} from this method indicates that the {@code AdviceMode} 084 * could not be handled or was unknown and that an {@code IllegalArgumentException} 085 * should be thrown. 086 * @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName() 087 * advice mode attribute} for the annotation specified via generics. 088 * @return array containing classes to import (empty array if none; 089 * {@code null} if the given {@code AdviceMode} is unknown) 090 */ 091 protected abstract String[] selectImports(AdviceMode adviceMode); 092 093}