Skip to content

Create AllNestedConditions and NoneNestedConditions based on AnyNestedCondition #2400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package org.springframework.boot.autoconfigure.condition;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

public abstract class AbstractNestedCondition extends SpringBootCondition implements
ConfigurationCondition {

private final ConfigurationPhase configurationPhase;

public AbstractNestedCondition(ConfigurationPhase configurationPhase) {
Assert.notNull(configurationPhase, "ConfigurationPhase must not be null");
this.configurationPhase = configurationPhase;
}

@Override
public ConfigurationPhase getConfigurationPhase() {
return this.configurationPhase;
}

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
MemberConditions memberConditions = new MemberConditions(context, getClass()
.getName());
List<ConditionOutcome> outcomes = memberConditions.getMatchOutcomes();
return buildConditionOutcome(outcomes);
}

protected abstract ConditionOutcome buildConditionOutcome(
List<ConditionOutcome> outcomes);

private static class MemberConditions {

private final ConditionContext context;

private final MetadataReaderFactory readerFactory;

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

public MemberConditions(ConditionContext context, String className) {
this.context = context;
this.readerFactory = new SimpleMetadataReaderFactory(
context.getResourceLoader());
String[] members = getMetadata(className).getMemberClassNames();
this.memberConditions = getMemberConditions(members);
}

private Map<AnnotationMetadata, List<Condition>> getMemberConditions(
String[] members) {
MultiValueMap<AnnotationMetadata, Condition> memberConditions = new LinkedMultiValueMap<AnnotationMetadata, Condition>();
for (String member : members) {
AnnotationMetadata metadata = getMetadata(member);
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass);
memberConditions.add(metadata, condition);
}
}
}
return Collections.unmodifiableMap(memberConditions);
}

private AnnotationMetadata getMetadata(String className) {
try {
return this.readerFactory.getMetadataReader(className)
.getAnnotationMetadata();
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}

@SuppressWarnings("unchecked")
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attributes = metadata
.getAllAnnotationAttributes(Conditional.class.getName(), true);
Object values = (attributes != null ? attributes.get("value") : null);
return (List<String[]>) (values != null ? values : Collections.emptyList());
}

private Condition getCondition(String conditionClassName) {
Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName,
this.context.getClassLoader());
return (Condition) BeanUtils.instantiateClass(conditionClass);
}

public List<ConditionOutcome> getMatchOutcomes() {
List<ConditionOutcome> outcomes = new ArrayList<ConditionOutcome>();
for (Map.Entry<AnnotationMetadata, List<Condition>> entry : this.memberConditions
.entrySet()) {
AnnotationMetadata metadata = entry.getKey();
for (Condition condition : entry.getValue()) {
outcomes.add(getConditionOutcome(metadata, condition));
}
}
return Collections.unmodifiableList(outcomes);
}

private ConditionOutcome getConditionOutcome(AnnotationMetadata metadata,
Condition condition) {
String messagePrefix = "member condition on " + metadata.getClassName();
if (condition instanceof SpringBootCondition) {
ConditionOutcome outcome = ((SpringBootCondition) condition)
.getMatchOutcome(this.context, metadata);
String message = outcome.getMessage();
return new ConditionOutcome(outcome.isMatch(), messagePrefix
+ (StringUtils.hasLength(message) ? " : " + message : ""));
}
boolean matches = condition.matches(this.context, metadata);
return new ConditionOutcome(matches, messagePrefix);
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.springframework.boot.autoconfigure.condition;

import java.util.ArrayList;
import java.util.List;

public abstract class AllNestedConditions extends AbstractNestedCondition {

public AllNestedConditions(ConfigurationPhase configurationPhase) {
super(configurationPhase);
}

@Override
protected ConditionOutcome buildConditionOutcome(List<ConditionOutcome> outcomes) {
List<ConditionOutcome> match = new ArrayList<ConditionOutcome>();
List<ConditionOutcome> nonMatch = new ArrayList<ConditionOutcome>();
for (ConditionOutcome outcome : outcomes) {
if (outcome.isMatch()) {
match.add(outcome);
}
else {
nonMatch.add(outcome);
}
}
return new ConditionOutcome(match.size() == outcomes.size(),
"all match resulted in " + match + " matches and " + nonMatch
+ " non matches");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,167 +16,54 @@

package org.springframework.boot.autoconfigure.condition;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.ConfigurationCondition;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

/**
* {@link Condition} that will match when any nested class condition matches. Can be used
* to create composite conditions, for example:
* {@link Condition} that will match when any nested class condition matches.
* Can be used to create composite conditions, for example:
*
* <pre class="code">
* static class OnJndiOrProperty extends AnyNestedCondition {
*
*
* &#064ConditionalOnJndi()
* static class OnJndi {
* static class OnJndi {
* }

*
* &#064ConditionalOnProperty("something")
* static class OnProperty {
* }
*
*
* }
* </pre>
*
* @author Phillip Webb
* @since 1.2.0
*/
@Order(Ordered.LOWEST_PRECEDENCE - 20)
public abstract class AnyNestedCondition extends SpringBootCondition implements
ConfigurationCondition {

private final ConfigurationPhase configurationPhase;
public abstract class AnyNestedCondition extends AbstractNestedCondition {

public AnyNestedCondition(ConfigurationPhase configurationPhase) {
Assert.notNull(configurationPhase, "ConfigurationPhase must not be null");
this.configurationPhase = configurationPhase;
super(configurationPhase);
}

@Override
public ConfigurationPhase getConfigurationPhase() {
return this.configurationPhase;
}

@Override
public ConditionOutcome getMatchOutcome(ConditionContext context,
AnnotatedTypeMetadata metadata) {
MemberConditions memberConditions = new MemberConditions(context, getClass()
.getName());
List<ConditionOutcome> outcomes = memberConditions.getMatchOutcomes();
protected ConditionOutcome buildConditionOutcome(List<ConditionOutcome> outcomes) {
List<ConditionOutcome> match = new ArrayList<ConditionOutcome>();
List<ConditionOutcome> nonMatch = new ArrayList<ConditionOutcome>();
for (ConditionOutcome outcome : outcomes) {
if (outcome.isMatch()) {
match.add(outcome);
}
else {
} else {
nonMatch.add(outcome);
}
}
return new ConditionOutcome(match.size() > 0, "any match resulted in " + match
+ " matches and " + nonMatch + " non matches");
}

private static class MemberConditions {

private final ConditionContext context;

private final MetadataReaderFactory readerFactory;

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

public MemberConditions(ConditionContext context, String className) {
this.context = context;
this.readerFactory = new SimpleMetadataReaderFactory(
context.getResourceLoader());
String[] members = getMetadata(className).getMemberClassNames();
this.memberConditions = getMemberConditions(members);
}

private Map<AnnotationMetadata, List<Condition>> getMemberConditions(
String[] members) {
MultiValueMap<AnnotationMetadata, Condition> memberConditions = new LinkedMultiValueMap<AnnotationMetadata, Condition>();
for (String member : members) {
AnnotationMetadata metadata = getMetadata(member);
for (String[] conditionClasses : getConditionClasses(metadata)) {
for (String conditionClass : conditionClasses) {
Condition condition = getCondition(conditionClass);
memberConditions.add(metadata, condition);
}
}
}
return Collections.unmodifiableMap(memberConditions);
}

private AnnotationMetadata getMetadata(String className) {
try {
return this.readerFactory.getMetadataReader(className)
.getAnnotationMetadata();
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}

@SuppressWarnings("unchecked")
private List<String[]> getConditionClasses(AnnotatedTypeMetadata metadata) {
MultiValueMap<String, Object> attributes = metadata
.getAllAnnotationAttributes(Conditional.class.getName(), true);
Object values = (attributes != null ? attributes.get("value") : null);
return (List<String[]>) (values != null ? values : Collections.emptyList());
}

private Condition getCondition(String conditionClassName) {
Class<?> conditionClass = ClassUtils.resolveClassName(conditionClassName,
this.context.getClassLoader());
return (Condition) BeanUtils.instantiateClass(conditionClass);
}

public List<ConditionOutcome> getMatchOutcomes() {
List<ConditionOutcome> outcomes = new ArrayList<ConditionOutcome>();
for (Map.Entry<AnnotationMetadata, List<Condition>> entry : this.memberConditions
.entrySet()) {
AnnotationMetadata metadata = entry.getKey();
for (Condition condition : entry.getValue()) {
outcomes.add(getConditionOutcome(metadata, condition));
}
}
return Collections.unmodifiableList(outcomes);
}

private ConditionOutcome getConditionOutcome(AnnotationMetadata metadata,
Condition condition) {
String messagePrefix = "member condition on " + metadata.getClassName();
if (condition instanceof SpringBootCondition) {
ConditionOutcome outcome = ((SpringBootCondition) condition)
.getMatchOutcome(this.context, metadata);
String message = outcome.getMessage();
return new ConditionOutcome(outcome.isMatch(), messagePrefix
+ (StringUtils.hasLength(message) ? " : " + message : ""));
}
boolean matches = condition.matches(this.context, metadata);
return new ConditionOutcome(matches, messagePrefix);
}

return new ConditionOutcome(match.size() > 0, "any match resulted in " + match + " matches and " + nonMatch
+ " non matches");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.springframework.boot.autoconfigure.condition;

import java.util.ArrayList;
import java.util.List;

public abstract class NoneOfNestedConditions extends AbstractNestedCondition {

public NoneOfNestedConditions(ConfigurationPhase configurationPhase) {
super(configurationPhase);
}

@Override
protected ConditionOutcome buildConditionOutcome(List<ConditionOutcome> outcomes) {
List<ConditionOutcome> match = new ArrayList<ConditionOutcome>();
List<ConditionOutcome> nonMatch = new ArrayList<ConditionOutcome>();
for (ConditionOutcome outcome : outcomes) {
if (outcome.isMatch()) {
match.add(outcome);
} else {
nonMatch.add(outcome);
}
}
return new ConditionOutcome(match.size() == 0, "none of match resulted in " + match + " matches and "
+ nonMatch + " non matches");
}

}
Loading