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

TAKETODAY / today-infrastructure / 19387509749

15 Nov 2025 09:04AM UTC coverage: 84.116% (-0.003%) from 84.119%
19387509749

push

github

web-flow
Java 25

Java 25

61360 of 78051 branches covered (78.62%)

Branch coverage included in aggregate %.

145107 of 167405 relevant lines covered (86.68%)

3.69 hits per line

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

94.92
today-context/src/main/java/infra/context/condition/AbstractNestedCondition.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.condition;
19

20
import java.io.IOException;
21
import java.util.ArrayList;
22
import java.util.Collections;
23
import java.util.List;
24
import java.util.Map;
25

26
import infra.beans.BeanUtils;
27
import infra.context.annotation.Condition;
28
import infra.context.annotation.ConditionContext;
29
import infra.context.annotation.Conditional;
30
import infra.context.annotation.ConfigurationCondition;
31
import infra.core.type.AnnotatedTypeMetadata;
32
import infra.core.type.AnnotationMetadata;
33
import infra.core.type.classreading.MetadataReaderFactory;
34
import infra.lang.Assert;
35
import infra.util.ClassUtils;
36
import infra.util.MultiValueMap;
37

38
/**
39
 * Abstract base class for nested conditions.
40
 *
41
 * @author Phillip Webb
42
 * @author <a href="https://github.com/TAKETODAY">Harry Yang</a>
43
 * @since 4.0 2022/1/16 17:55
44
 */
45
public abstract class AbstractNestedCondition extends InfraCondition implements ConfigurationCondition {
46

47
  private final ConfigurationPhase configurationPhase;
48

49
  AbstractNestedCondition(ConfigurationPhase configurationPhase) {
2✔
50
    Assert.notNull(configurationPhase, "ConfigurationPhase is required");
3✔
51
    this.configurationPhase = configurationPhase;
3✔
52
  }
1✔
53

54
  @Override
55
  public ConfigurationPhase getConfigurationPhase() {
56
    return this.configurationPhase;
3✔
57
  }
58

59
  @Override
60
  public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
61
    String className = getClass().getName();
4✔
62
    MemberConditions memberConditions = new MemberConditions(context, this.configurationPhase, className);
8✔
63
    MemberMatchOutcomes memberOutcomes = new MemberMatchOutcomes(memberConditions);
5✔
64
    return getFinalMatchOutcome(memberOutcomes);
4✔
65
  }
66

67
  protected abstract ConditionOutcome getFinalMatchOutcome(MemberMatchOutcomes memberOutcomes);
68

69
  protected static class MemberMatchOutcomes {
70

71
    public final List<ConditionOutcome> all;
72
    public final List<ConditionOutcome> matches;
73
    public final List<ConditionOutcome> nonMatches;
74

75
    public MemberMatchOutcomes(MemberConditions memberConditions) {
2✔
76
      this.all = memberConditions.getMatchOutcomes();
4✔
77
      ArrayList<ConditionOutcome> matches = new ArrayList<>();
4✔
78
      ArrayList<ConditionOutcome> nonMatches = new ArrayList<>();
4✔
79
      for (ConditionOutcome outcome : this.all) {
11✔
80
        (outcome.isMatch() ? matches : nonMatches).add(outcome);
9✔
81
      }
1✔
82
      this.matches = Collections.unmodifiableList(matches);
4✔
83
      this.nonMatches = Collections.unmodifiableList(nonMatches);
4✔
84
    }
1✔
85

86
  }
87

88
  private static class MemberConditions {
89

90
    private final ConditionContext context;
91
    private final MetadataReaderFactory readerFactory;
92

93
    private final Map<AnnotationMetadata, List<Condition>> memberConditions;
94

95
    MemberConditions(ConditionContext context, ConfigurationPhase phase, String className) {
2✔
96
      this.context = context;
3✔
97
      this.readerFactory = MetadataReaderFactory.create(context.getResourceLoader());
5✔
98
      String[] members = getMetadata(className).getMemberClassNames();
5✔
99
      this.memberConditions = getMemberConditions(members, phase, className);
7✔
100
    }
1✔
101

102
    private Map<AnnotationMetadata, List<Condition>> getMemberConditions(
103
            String[] members, ConfigurationPhase phase, String className) {
104
      var memberConditions = MultiValueMap.<AnnotationMetadata, Condition>forLinkedHashMap();
2✔
105
      for (String member : members) {
16✔
106
        AnnotationMetadata metadata = getMetadata(member);
4✔
107
        for (String[] conditionClasses : getConditionClasses(metadata)) {
12✔
108
          for (String conditionClass : conditionClasses) {
16✔
109
            Condition condition = getCondition(conditionClass);
4✔
110
            validateMemberCondition(condition, phase, className);
5✔
111
            memberConditions.add(metadata, condition);
4✔
112
          }
113
        }
1✔
114
      }
115
      return memberConditions;
2✔
116
    }
117

118
    private void validateMemberCondition(Condition condition, ConfigurationPhase nestedPhase, String nestedClassName) {
119
      if (nestedPhase == ConfigurationPhase.PARSE_CONFIGURATION
6✔
120
              && condition instanceof ConfigurationCondition ccd) {
3✔
121
        ConfigurationPhase memberPhase = ccd.getConfigurationPhase();
3✔
122
        if (memberPhase == ConfigurationPhase.REGISTER_BEAN) {
3!
123
          throw new IllegalStateException("Nested condition %s uses a configuration phase that is inappropriate for %s"
12✔
124
                  .formatted(nestedClassName, condition.getClass()));
5✔
125
        }
126
      }
127
    }
1✔
128

129
    private AnnotationMetadata getMetadata(String className) {
130
      try {
131
        return this.readerFactory.getMetadataReader(className).getAnnotationMetadata();
6✔
132
      }
133
      catch (IOException ex) {
×
134
        throw new IllegalStateException(ex);
×
135
      }
136
    }
137

138
    @SuppressWarnings("unchecked")
139
    private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
140
      var attributes = metadata.getAllAnnotationAttributes(Conditional.class, true);
5✔
141
      if (attributes != null) {
2!
142
        Object values = attributes.get("value");
4✔
143
        if (values != null) {
2!
144
          return (List<String[]>) values;
3✔
145
        }
146
      }
147
      return Collections.emptyList();
×
148
    }
149

150
    private Condition getCondition(String className) {
151
      var conditionClass = ClassUtils.<Condition>resolveClassName(className, context.getClassLoader());
6✔
152
      return BeanUtils.newInstance(conditionClass);
4✔
153
    }
154

155
    List<ConditionOutcome> getMatchOutcomes() {
156
      ArrayList<ConditionOutcome> outcomes = new ArrayList<>();
4✔
157
      for (Map.Entry<AnnotationMetadata, List<Condition>> entry : memberConditions.entrySet()) {
12✔
158
        AnnotationMetadata metadata = entry.getKey();
4✔
159
        List<Condition> conditions = entry.getValue();
4✔
160
        outcomes.add(new MemberOutcomes(context, metadata, conditions).getUltimateOutcome());
11✔
161
      }
1✔
162
      return Collections.unmodifiableList(outcomes);
3✔
163
    }
164

165
  }
166

167
  private static class MemberOutcomes {
168

169
    private final AnnotationMetadata metadata;
170
    private final List<ConditionOutcome> outcomes;
171
    private final ConditionContext context;
172

173
    MemberOutcomes(ConditionContext context, AnnotationMetadata metadata, List<Condition> conditions) {
2✔
174
      this.context = context;
3✔
175
      this.metadata = metadata;
3✔
176
      this.outcomes = new ArrayList<>(conditions.size());
7✔
177
      for (Condition condition : conditions) {
10✔
178
        this.outcomes.add(getConditionOutcome(metadata, condition));
8✔
179
      }
1✔
180
    }
1✔
181

182
    private ConditionOutcome getConditionOutcome(AnnotationMetadata metadata, Condition condition) {
183
      if (condition instanceof InfraCondition) {
3✔
184
        return ((InfraCondition) condition).getMatchOutcome(context, metadata);
7✔
185
      }
186
      return new ConditionOutcome(condition.matches(context, metadata), ConditionMessage.empty());
10✔
187
    }
188

189
    ConditionOutcome getUltimateOutcome() {
190
      var message = ConditionMessage.forCondition(
4✔
191
              "NestedCondition on " + ClassUtils.getShortName(metadata.getClassName()));
5✔
192
      if (outcomes.size() == 1) {
5✔
193
        ConditionOutcome outcome = outcomes.get(0);
6✔
194
        return new ConditionOutcome(outcome.isMatch(), message.because(outcome.getMessage()));
10✔
195
      }
196
      ArrayList<ConditionOutcome> match = new ArrayList<>();
4✔
197
      ArrayList<ConditionOutcome> nonMatch = new ArrayList<>();
4✔
198
      for (ConditionOutcome outcome : outcomes) {
11✔
199
        (outcome.isMatch() ? match : nonMatch).add(outcome);
9✔
200
      }
1✔
201
      if (nonMatch.isEmpty()) {
3✔
202
        return ConditionOutcome.match(message.found("matching nested conditions").items(match));
7✔
203
      }
204
      return ConditionOutcome.noMatch(message.found("non-matching nested conditions").items(nonMatch));
7✔
205
    }
206

207
  }
208

209
}
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