Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ConditionalOnProperty for lists or arrays?

I'm using Spring Boot 1.4.3 @AutoConfiguration where I create beans automatically based on properties user specifies. User can specify an array of services, where name and version are required fields:

service[0].name=myServiceA
service[0].version=1.0

service[1].name=myServiceB
service[1].version=1.2

...

If the user forgets to specify a required field on even just one service, I want to back-off and not create any beans. Can I accomplish this with @ConditionalOnProperty? I want something like:

@Configuration
@ConditionalOnProperty({"service[i].name", "service[i].version"})
class AutoConfigureServices {
....
} 
like image 878
Strumbles Avatar asked Oct 29 '22 13:10

Strumbles


1 Answers

This is the custom Condition I created. It needs some polishing to be more generic (ie not hardcoding strings), but worked great for me.

To use, I annotated my Configuration class with @Conditional(RequiredRepeatablePropertiesCondition.class)

public class RequiredRepeatablePropertiesCondition extends SpringBootCondition {

    private static final Logger LOGGER = LoggerFactory.getLogger(RequiredRepeatablePropertiesCondition.class.getName());

    public static final String[] REQUIRED_KEYS = {
            "my.services[i].version",
            "my.services[i].name"
    };

    @Override
    public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
        List<String> missingProperties = new ArrayList<>();
        RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(context.getEnvironment());
        Map<String, Object> services = resolver.getSubProperties("my.services");
        if (services.size() == 0) {
            missingProperties.addAll(Arrays.asList(REQUIRED_KEYS));
            return getConditionOutcome(missingProperties);
        }
        //gather indexes to check: [0], [1], [3], etc
        Pattern p = Pattern.compile("\\[(\\d+)\\]");
        Set<String> uniqueIndexes = new HashSet<String>();
        for (String key : services.keySet()) {
            Matcher m = p.matcher(key);
            if (m.find()) {
                uniqueIndexes.add(m.group(1));
            }
        }
        //loop each index and check required props
        uniqueIndexes.forEach(index -> {
            for (String genericKey : REQUIRED_KEYS) {
                String multiServiceKey = genericKey.replace("[i]", "[" + index + "]");
                if (!resolver.containsProperty(multiServiceKey)) {
                    missingProperties.add(multiServiceKey);
                }
            }
        });
        return getConditionOutcome(missingProperties);
    }

    private ConditionOutcome getConditionOutcome(List<String> missingProperties) {
        if (missingProperties.isEmpty()) {
            return ConditionOutcome.match(ConditionMessage.forCondition(RequiredRepeatablePropertiesCondition.class.getCanonicalName())
                    .found("property", "properties")
                    .items(Arrays.asList(REQUIRED_KEYS)));
        }
        return ConditionOutcome.noMatch(
                ConditionMessage.forCondition(RequiredRepeatablePropertiesCondition.class.getCanonicalName())
            .didNotFind("property", "properties")
            .items(missingProperties)
        );
    }
}
like image 143
Strumbles Avatar answered Nov 02 '22 22:11

Strumbles