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; 024import org.springframework.lang.Nullable; 025import org.springframework.util.Assert; 026 027/** 028 * Convenient base class for {@link ImportSelector} implementations that select imports 029 * based on an {@link AdviceMode} value from an annotation (such as the {@code @Enable*} 030 * annotations). 031 * 032 * @author Chris Beams 033 * @since 3.1 034 * @param <A> annotation containing {@linkplain #getAdviceModeAttributeName() AdviceMode attribute} 035 */ 036public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector { 037 038 /** 039 * The default advice mode attribute name. 040 */ 041 public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode"; 042 043 044 /** 045 * The name of the {@link AdviceMode} attribute for the annotation specified by the 046 * generic type {@code A}. The default is {@value #DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME}, 047 * but subclasses may override in order to customize. 048 */ 049 protected String getAdviceModeAttributeName() { 050 return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME; 051 } 052 053 /** 054 * This implementation resolves the type of annotation from generic metadata and 055 * validates that (a) the annotation is in fact present on the importing 056 * {@code @Configuration} class and (b) that the given annotation has an 057 * {@linkplain #getAdviceModeAttributeName() advice mode attribute} of type 058 * {@link AdviceMode}. 059 * <p>The {@link #selectImports(AdviceMode)} method is then invoked, allowing the 060 * concrete implementation to choose imports in a safe and convenient fashion. 061 * @throws IllegalArgumentException if expected annotation {@code A} is not present 062 * on the importing {@code @Configuration} class or if {@link #selectImports(AdviceMode)} 063 * returns {@code null} 064 */ 065 @Override 066 public final String[] selectImports(AnnotationMetadata importingClassMetadata) { 067 Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class); 068 Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector"); 069 070 AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); 071 if (attributes == null) { 072 throw new IllegalArgumentException(String.format( 073 "@%s is not present on importing class '%s' as expected", 074 annType.getSimpleName(), importingClassMetadata.getClassName())); 075 } 076 077 AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName()); 078 String[] imports = selectImports(adviceMode); 079 if (imports == null) { 080 throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode); 081 } 082 return imports; 083 } 084 085 /** 086 * Determine which classes should be imported based on the given {@code AdviceMode}. 087 * <p>Returning {@code null} from this method indicates that the {@code AdviceMode} 088 * could not be handled or was unknown and that an {@code IllegalArgumentException} 089 * should be thrown. 090 * @param adviceMode the value of the {@linkplain #getAdviceModeAttributeName() 091 * advice mode attribute} for the annotation specified via generics. 092 * @return array containing classes to import (empty array if none; 093 * {@code null} if the given {@code AdviceMode} is unknown) 094 */ 095 @Nullable 096 protected abstract String[] selectImports(AdviceMode adviceMode); 097 098}