В мире Spring Boot почти каждый сталкивался с аннотациями @ConditionalOnProperty, @ConditionalOnBean и их собратьями. Они помогают конфигурировать бины динамически, но стандартные условия это только вершина айсберга. Что если вам нужен гибкий, декларативный, строго-типизированный, который понимает Collection, Map, Enum и т.д.?
Именно для этого я разработал conditionals-spring-boot - маленькую библиотеку для расширенных conditional-аннотаций, полностью интегрируемую с Spring Boot 3 и Java 17.
Почему стандартные условия не всегда работают
В Spring Boot @ConditionalOnProperty позволяет проверять простые свойства, но:
Нельзя писать простые сравнения и матчи с помощью аннотаций (
@ConditionalOnExpressionне в счет).Нельзя строго типизировать значение (в обычном Spring Boot есть только String и boolean).
Что умеет моя библиотека

1. Поддержка многих часто используемых типов:
Ниже можно увидеть несколько примеров использования аннотаций библиотеки:
@ConditionalOnStringProperty
@ConditionalOnStringProperty( name = "app.region", havingValue = "eu", trim = true )
@ConditionalOnStringProperty( name = "app.region", havingValue = "EU", ignoreCase = true )
@ConditionalOnStringProperty( name = "app.version", havingValue = "v\\d+\\.\\d+", matchType = StringMatchType.MATCHES )
@ConditionalOnIntegerProperty
@ConditionalOnIntegerProperty( name = "app.threads", havingValue = 4 )
@ConditionalOnIntegerProperty( name = "app.threads", havingValue = 16, matchType = ComparableMatchType.LESS_THAN )
@ConditionalOnFloatProperty
@ConditionalOnFloatProperty( name = "app.ratio", havingValue = 0.5f )
@ConditionalOnFloatProperty( name = "app.ratio", havingValue = 0.7F, matchType = ComparableMatchType.GREATER_THAN_OR_EQUAL )
@ConditionalOnDurationProperty
@ConditionalOnDurationProperty( name = "app.timeout", havingValue = "5s", matchType = ComparableMatchType.GREATER_THAN )
@ConditionalOnDurationProperty( name = "app.timeout", havingValue = "10s" )
@ConditionalOnCharacterProperty
@ConditionalOnCharacterProperty( name = "app.letter", havingValue = 'A' )
@ConditionalOnCollectionProperty
@ConditionalOnCollectionProperty( name = "app.tags", havingValue = {"red", "blue"}, matchType = CollectionMatchType.CONTAINS_ALL )
@ConditionalOnCollectionProperty( name = "app.tags", havingValue = {"yellow", "green"}, matchType = CollectionMatchType.CONTAINS_ANY )
@ConditionalOnCollectionProperty( name = "app.tags", size = 3 )
@ConditionalOnMapProperty
@ConditionalOnMapProperty( name = "app.labels", havingValue = { // массив ключ-значение "env", "prod", "region", "eu" }, matchType = MapMatchType.CONTAINS_ALL )
@ConditionalOnMapProperty( name = "app.labels", havingValue = {"env", "prod"}, // массив ключ-значение matchType = MapMatchType.CONTAINS_ANY )
@ConditionalOnEnumProperty
@ConditionalOnEnumProperty( name = "app.labels", havingValue = "info", // не кейс-сенситив enumType = LogLevel.class ) enum LogLevel { TRACE, DEBUG, INFO, WARN, ERROR }
2. Repeatable и контейнерные аннотации
Практически все аннотации можно повторять (кроме @ConditionalOnOs и @ConditionalOnPortAvailable).
3. Унифицированная спецификация через PropertySpec
4. Проверку ОС:
@ConditionalOnOs("linux")
5. Проверку занятости порта:
@ConditionalOnPortAvailable(8080)
Внутри библиотеки все property-based условия описаны через единый контракт PropertySpec + PropertySpecMatcher. Это минимизирует копипасту и упрощает тестирование.
Кому это будет полезно
Разработчикам библиотек и модулей для Spring Boot.
Командам, которые пишут DSL на основе configuration properties.
Тем, кто сталкивался с boilerplate и ограничениями стандартных
@Conditionalаннотаций.
Заключение
Если вам интересно попробовать, документация и примеры доступны на GitHub. (и поставьте звёздочку :D)
