• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TAKETODAY / today-infrastructure / 18154768944

01 Oct 2025 07:26AM UTC coverage: 81.882% (-0.005%) from 81.887%
18154768944

push

github

web-flow
Merge pull request #290 from TAKETODAY/dev/jspecify

jspecify

59788 of 78013 branches covered (76.64%)

Branch coverage included in aggregate %.

141239 of 167496 relevant lines covered (84.32%)

3.6 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.0
today-context/src/main/java/infra/context/annotation/config/ImportAutoConfigurationImportSelector.java
1
/*
2
 * Copyright 2017 - 2025 the original author or authors.
3
 *
4
 * This program is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program. If not, see [https://www.gnu.org/licenses/]
16
 */
17

18
package infra.context.annotation.config;
19

20
import org.jspecify.annotations.Nullable;
21

22
import java.lang.annotation.Annotation;
23
import java.util.ArrayList;
24
import java.util.Arrays;
25
import java.util.Collection;
26
import java.util.Collections;
27
import java.util.HashSet;
28
import java.util.LinkedHashSet;
29
import java.util.List;
30
import java.util.Map;
31
import java.util.Objects;
32
import java.util.Set;
33

34
import infra.core.annotation.AnnotationAttributes;
35
import infra.core.annotation.AnnotationUtils;
36
import infra.core.annotation.MergedAnnotation;
37
import infra.core.annotation.MergedAnnotations;
38
import infra.core.io.ClassPathResource;
39
import infra.core.type.AnnotationMetadata;
40
import infra.lang.TodayStrategies;
41
import infra.util.ClassUtils;
42
import infra.util.CollectionUtils;
43
import infra.util.MultiValueMap;
44
import infra.util.ObjectUtils;
45

46
/**
47
 * Variant of {@link AutoConfigurationImportSelector} for
48
 * {@link ImportAutoConfiguration @ImportAutoConfiguration}.
49
 *
50
 * @author Phillip Webb
51
 * @author Andy Wilkinson
52
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
53
 * @since 4.0 2022/2/1 23:56
54
 */
55
public class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports {
3✔
56

57
  private static final String OPTIONAL_PREFIX = "optional:";
58

59
  @Override
60
  public Set<Object> determineImports(AnnotationMetadata metadata) {
61
    List<String> candidateConfigurations = getCandidateConfigurations(metadata, null);
5✔
62
    LinkedHashSet<String> result = new LinkedHashSet<>(candidateConfigurations);
5✔
63
    result.removeAll(getExclusions(metadata, null));
7✔
64
    return Collections.unmodifiableSet(result);
3✔
65
  }
66

67
  @Override
68
  @Nullable
69
  protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
70
    return null;
2✔
71
  }
72

73
  @Override
74
  protected List<String> getCandidateConfigurations(
75
          AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {
76
    ArrayList<String> candidates = new ArrayList<>();
4✔
77

78
    Map<Class<?>, List<Annotation>> annotations = getAnnotations(metadata);
4✔
79
    for (Map.Entry<Class<?>, List<Annotation>> entry : annotations.entrySet()) {
11✔
80
      Class<?> source = entry.getKey();
4✔
81
      List<Annotation> sourceAnnotations = entry.getValue();
4✔
82
      collectCandidateConfigurations(source, sourceAnnotations, candidates);
5✔
83
    }
1✔
84
    return candidates;
2✔
85
  }
86

87
  private void collectCandidateConfigurations(Class<?> source,
88
          List<Annotation> annotations, List<String> candidates) {
89
    for (Annotation annotation : annotations) {
10✔
90
      candidates.addAll(getConfigurationsForAnnotation(source, annotation));
7✔
91
    }
1✔
92
  }
1✔
93

94
  private Collection<String> getConfigurationsForAnnotation(Class<?> source, Annotation annotation) {
95
    String[] classes = MergedAnnotation.from(annotation).getStringArray("classes");
5✔
96
    if (classes.length > 0) {
3✔
97
      return Arrays.asList(classes);
3✔
98
    }
99
    Collection<String> strategiesNames = getStrategiesNames(source);
4✔
100
    return strategiesNames.stream()
5✔
101
            .map((name) -> {
2✔
102
              if (name.startsWith(OPTIONAL_PREFIX)) {
4✔
103
                name = name.substring(OPTIONAL_PREFIX.length());
5✔
104
                if (!present(name)) {
4✔
105
                  return null;
2✔
106
                }
107
              }
108
              return name;
2✔
109
            })
110
            .filter(Objects::nonNull)
1✔
111
            .toList();
1✔
112
  }
113

114
  protected Collection<String> getStrategiesNames(Class<?> source) {
115
    ClassLoader beanClassLoader = getBeanClassLoader();
3✔
116
    ArrayList<String> strategies = ImportCandidates.load(source, beanClassLoader).getCandidates();
5✔
117
    strategies.addAll(TodayStrategies.findNames(source.getName(), beanClassLoader));
7✔
118
    return strategies;
2✔
119
  }
120

121
  private boolean present(String className) {
122
    String resourcePath = ClassUtils.convertClassNameToResourcePath(className) + ".class";
4✔
123
    return new ClassPathResource(resourcePath).exists();
6✔
124
  }
125

126
  @Override
127
  protected Set<String> getExclusions(AnnotationMetadata metadata, @Nullable AnnotationAttributes attributes) {
128
    LinkedHashSet<String> exclusions = new LinkedHashSet<>();
4✔
129
    Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
5✔
130

131
    var merged = MergedAnnotations.from(source).get(ImportAutoConfiguration.class);
5✔
132
    if (merged.isPresent()) {
3!
133
      Class<?>[] exclude = merged.getClassArray("exclude");
4✔
134
      if (exclude != null) {
2!
135
        for (Class<?> excludeClass : exclude) {
16✔
136
          exclusions.add(excludeClass.getName());
5✔
137
        }
138
      }
139
    }
140

141
    for (List<Annotation> annotations : getAnnotations(metadata).values()) {
13✔
142
      for (Annotation annotation : annotations) {
10✔
143
        String[] excludes = MergedAnnotation.from(annotation).getStringArray("exclude");
5✔
144
        if (ObjectUtils.isNotEmpty(excludes)) {
3✔
145
          CollectionUtils.addAll(exclusions, excludes);
3✔
146
        }
147
      }
1✔
148
    }
1✔
149
    exclusions.addAll(getExcludeAutoConfigurationsProperty());
5✔
150
    return exclusions;
2✔
151
  }
152

153
  protected final Map<Class<?>, List<Annotation>> getAnnotations(AnnotationMetadata metadata) {
154
    MultiValueMap<Class<?>, Annotation> annotations = MultiValueMap.forLinkedHashMap();
2✔
155
    Class<?> source = ClassUtils.resolveClassName(metadata.getClassName(), null);
5✔
156
    collectAnnotations(source, annotations, new HashSet<>());
7✔
157
    return Collections.unmodifiableMap(annotations);
3✔
158
  }
159

160
  private void collectAnnotations(Class<?> source,
161
          MultiValueMap<Class<?>, Annotation> annotations, HashSet<Class<?>> seen) {
162
    if (source != null && seen.add(source)) {
6✔
163
      for (Annotation annotation : source.getDeclaredAnnotations()) {
17✔
164
        if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
3✔
165
          if (ImportAutoConfiguration.class == annotation.annotationType()) {
4✔
166
            annotations.add(source, annotation);
4✔
167
          }
168
          collectAnnotations(annotation.annotationType(), annotations, seen);
6✔
169
        }
170
      }
171
      collectAnnotations(source.getSuperclass(), annotations, seen);
6✔
172
    }
173
  }
1✔
174

175
  @Override
176
  public int getOrder() {
177
    return super.getOrder() - 1;
×
178
  }
179

180
  @Override
181
  protected void handleInvalidExcludes(List<String> invalidExcludes) {
182
    // Ignore for test
183
  }
1✔
184

185
}
186

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc