001/* 002 * Copyright 2002-2020 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 org.springframework.core.type.AnnotationMetadata; 020import org.springframework.lang.Nullable; 021 022/** 023 * A variation of {@link ImportSelector} that runs after all {@code @Configuration} beans 024 * have been processed. This type of selector can be particularly useful when the selected 025 * imports are {@code @Conditional}. 026 * 027 * <p>Implementations can also extend the {@link org.springframework.core.Ordered} 028 * interface or use the {@link org.springframework.core.annotation.Order} annotation to 029 * indicate a precedence against other {@link DeferredImportSelector DeferredImportSelectors}. 030 * 031 * <p>Implementations may also provide an {@link #getImportGroup() import group} which 032 * can provide additional sorting and filtering logic across different selectors. 033 * 034 * @author Phillip Webb 035 * @author Stephane Nicoll 036 * @since 4.0 037 */ 038public interface DeferredImportSelector extends ImportSelector { 039 040 /** 041 * Return a specific import group. 042 * <p>The default implementations return {@code null} for no grouping required. 043 * @return the import group class, or {@code null} if none 044 * @since 5.0 045 */ 046 @Nullable 047 default Class<? extends Group> getImportGroup() { 048 return null; 049 } 050 051 052 /** 053 * Interface used to group results from different import selectors. 054 * @since 5.0 055 */ 056 interface Group { 057 058 /** 059 * Process the {@link AnnotationMetadata} of the importing @{@link Configuration} 060 * class using the specified {@link DeferredImportSelector}. 061 */ 062 void process(AnnotationMetadata metadata, DeferredImportSelector selector); 063 064 /** 065 * Return the {@link Entry entries} of which class(es) should be imported 066 * for this group. 067 */ 068 Iterable<Entry> selectImports(); 069 070 071 /** 072 * An entry that holds the {@link AnnotationMetadata} of the importing 073 * {@link Configuration} class and the class name to import. 074 */ 075 class Entry { 076 077 private final AnnotationMetadata metadata; 078 079 private final String importClassName; 080 081 public Entry(AnnotationMetadata metadata, String importClassName) { 082 this.metadata = metadata; 083 this.importClassName = importClassName; 084 } 085 086 /** 087 * Return the {@link AnnotationMetadata} of the importing 088 * {@link Configuration} class. 089 */ 090 public AnnotationMetadata getMetadata() { 091 return this.metadata; 092 } 093 094 /** 095 * Return the fully qualified name of the class to import. 096 */ 097 public String getImportClassName() { 098 return this.importClassName; 099 } 100 101 @Override 102 public boolean equals(@Nullable Object other) { 103 if (this == other) { 104 return true; 105 } 106 if (other == null || getClass() != other.getClass()) { 107 return false; 108 } 109 Entry entry = (Entry) other; 110 return (this.metadata.equals(entry.metadata) && this.importClassName.equals(entry.importClassName)); 111 } 112 113 @Override 114 public int hashCode() { 115 return (this.metadata.hashCode() * 31 + this.importClassName.hashCode()); 116 } 117 118 @Override 119 public String toString() { 120 return this.importClassName; 121 } 122 } 123 } 124 125}