Search code examples
springvalidationspring-bootspring-config

Why are spring beans validated even if the condition says it should not be loaded into the context?


Given the example below, I would expect MyConfig.getSrvConfig() would not be called and therefore no validation would be executed on the returned object neither. But for some reason the validation is executed and the test case fails. Is there anything wrong in this setup?

I know the test would pass if I have private MySrvConfigBean srvConfig not initialized at declaration - but I really don't want MySrvConfigBean to be a standalone class with a @ConfigurationProperties(prefix = "cfg.srvConfig") annotation.

@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { TestCaseConfiguration.class })
public class ConditionalConfigValidationTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    public void test() {
        assertNotNull(applicationContext);
        assertFalse("srvConfig must NOT be in context", applicationContext.containsBean("srvConfig"));
    }

    @Configuration
    @EnableConfigurationProperties(value = { MyConfig.class })
    public static class TestCaseConfiguration {
    }

    @Component
    @Validated
    @ConfigurationProperties(prefix = "cfg")
    public static class MyConfig {
        private MySrvConfigBean srvConfig = new MySrvConfigBean();

        @Bean
        @Valid
        @Conditional(MyCondition.class)
        public MySrvConfigBean getSrvConfig() {
            return srvConfig;
        }

        public static class MySrvConfigBean {

            @NotNull
            private String name;

            public String getName() {
                return name;
            }
        }
    }

    public static class MyCondition implements Condition {
        @Override
        public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
            return false;
        }
    }
}

The reason we would like to have it this way is, because we then are able to structure configuration in code the same way as we have it in the YAML file, e.g.: (cfg and cfgA are the "root" objects for two different configuration hierarchies).

cfg:
  srvConfig: 
    name: Dude
  clientConfig: 
    xxx: true
    yyy: Muster
cfgA:
  aaaConfig:
    bbb: false
    ccc: Dundy
  dddConfig:  
    fff: 3

It feels like the execution of the validation (triggered by @Valid on getSrvConfig()) is a bug in this case.


Solution

  • Apparently this is not supported and should be solved in a different way:

    @Configuration
    @Conditional(MyCondition.class)
    @EnableConfigurationProperties(value = { MyConfig.class })
    public static class TestCaseConfiguration {
    }