Referring to ConfigurationProperties Beans in SpEL expression in @Configuration bean

爷,独闯天下 提交于 2019-12-10 16:46:57

问题


I have this properties class:

import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("some")
    public class SomeProperties {
        private List<String> stuff;

        public List<String> getStuff() {
            return stuff;
        }

        public void setStuff(List<String> stuff) {
            this.stuff = stuff;
        }    
    }

and I enable configuration properties in an @Configuration class like so:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(SomeProperties.class)
public class SomeAutoConfiguration {    
}

In the same class ("SomeAutoConfiguration") I want to create another bean depending if the list attribute in SomeProperties is empty or not. I thought i could use @ConditionalExpression with the following SpEl:

@Bean
@ConditionalOnExpression("!(#someProperties.stuff?.isEmpty()?:true)")   
    public Object someBean(final SomeProperties someProperties) {
    return new Object();
}    

The SpEl is correct, but i don't manage to get a hold of the bean containing my properties. Using the above expression i run into

EL1007E:(pos 43): Property or field 'stuff' cannot be found on null

And trying to get the bean through its name like

@Bean
@ConditionalOnExpression("!(@'some.CONFIGURATION_PROPERTIES'.stuff?.isEmpty()?:true)")  
    public Object someBean(final SomeProperties someProperties) {
    return new Object();
} 

ends up in

NoSuchBeanDefinitionException: No bean named 'some.CONFIGURATION_PROPERTIES' is defined

Any ideas? I already tried enabling ConfigurationProperties in another class but that didn't work either.


回答1:


I think the problem that you're facing is that @Conditions are evaluated when @Configuration classes are parsed, so there isn't any guarantee that the SomeProperties bean has been defined. Even if it were defined, you probably don't want it to be initialized early so I'd recommend a different approach.

You could try @ConditionalOnPropety, that's the annotation that is used internally by Spring Boot whenever it conditionally wants to enable auto-configuration based on a property. If that's not quite flexible enough you can create your own Condition and access the Environment directly to tell if the property value is empty. If you want to support flexible binding you can use RelaxedPropertyResolver. Here's an example.




回答2:


To complement @PhilWebb answer in regard of Spring Boot 2+, RelaxedPropertyResolver has been removed in favor of a more robust alternative named Binder. Here's a very simple example :

@Configuration
@AutoConfigureBefore(JacksonAutoConfiguration.class)
@ConditionalOnMissingBean(ObjectMapper.class)
@Conditional(SpringJacksonPropertiesMissing.class)
public class ObjectMapperConfiguration {
    @Bean
    public ObjectMapper objectMapper() {
        return new ObjectMapper()
                .disable(FAIL_ON_UNKNOWN_PROPERTIES)
                .setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    static class SpringJacksonPropertiesMissing extends SpringBootCondition {
        @Override
        public ConditionOutcome getMatchOutcome(ConditionContext context,
                                                AnnotatedTypeMetadata metadata) {
            return new ConditionOutcome(hasJacksonPropertiesDefined(context),
                                        "Spring Jackson property based configuration missing");
        }

        private boolean hasJackonPropertiesDefined(ConditionContext context) {
            return Binder.get(context.getEnvironment())
                         .bind(ConfigurationPropertyName.of("spring.jackson"),
                                                Bindable.of(Map.class))
                         .orElse(Collections.emptyMap())
                         .isEmpty();
        }
    }
}

DISCLAIMER: This code is used to phase out some bad practice regarding jackson object mapper, in order to transition some code to the spring boot way to configure an object mapper.



来源:https://stackoverflow.com/questions/31500794/referring-to-configurationproperties-beans-in-spel-expression-in-configuration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!