Skip to content

Latest commit

 

History

History
140 lines (95 loc) · 5.76 KB

conditionalBeans.adoc

File metadata and controls

140 lines (95 loc) · 5.76 KB

At times, you may want a bean to load conditionally based on various potential factors including the classpath, the configuration, the presence of other beans, etc.

The Requires annotation provides the ability to define one or many conditions on a bean.

Consider the following example:

snippet::io.micronaut.docs.requires.JdbcBookService[tags="requires",indent=0, title="Using @Requires"]

The above bean defines two requirements. The first indicates that a DataSource bean must be present for the bean to load. The second requirement ensures that the datasource.url property is set before loading the JdbcBookService bean.

If multiple beans require the same combination of requirements, you can define a meta-annotation with the requirements:

snippet::io.micronaut.docs.requires.RequiresJdbc[tags="annotation",indent=0, title="Using a @Requires meta-annotation"]

In the above example the RequiresJdbc annotation can be used on the JdbcBookService instead:

Using a meta-annotation
@RequiresJdbc
public class JdbcBookService implements BookService {
    ...
}

If you have multiple beans that need to fulfill a given requirement before loading, you may want to consider a bean configuration group, as explained in the next section.

Configuration Requirements

The @Requires annotation is very flexible and can be used for a variety of use cases. The following table summarizes some possibilities:

Table 1. Using @Requires
Requirement Example

Require the presence of one or more classes

@Requires(classes=javax.servlet.Servlet)

Require the absence of one or more classes

@Requires(missing=javax.servlet.Servlet)

Require the presence one or more beans

@Requires(beans=javax.sql.DataSource)

Require the absence of one or more beans

@Requires(missingBeans=javax.sql.DataSource)

Require the environment to be applied

@Requires(env="test")

Require the environment to not be applied

@Requires(notEnv="test")

Require the presence of another configuration package

@Requires(configuration="foo.bar")

Require the absence of another configuration package

@Requires(missingConfigurations="foo.bar")

Require particular SDK version

@Requires(sdk=Sdk.JAVA, value="1.8")

Requires classes annotated with the given annotations to be available to the application via package scanning

@Requires(entities=javax.persistence.Entity)

Require a property with an optional value

@Requires(property="data-source.url")

Require a property to not be part of the configuration

@Requires(missingProperty="data-source.url")

Require the presence of one or more files in the file system

@Requires(resources="file:/path/to/file")

Require the presence of one or more classpath resources

@Requires(resources="classpath:myFile.properties")

Require the current operating system to be in the list

@Requires(os={Requires.Family.WINDOWS})

Require the current operating system to not be in the list

@Requires(notOs={Requires.Family.WINDOWS})

Requires bean to be present in case no beanProperty specified

@Requires(bean=Config.class)

Requires the specified property of bean to be present

@Requires(bean=Config.class, beanProperty="enabled")

Additional Notes on Property Requirements.

Adding a requirement on a property has some additional functionality. You can require the property to be a certain value, not be a certain value, and use a default in those checks if it is not set.

@Requires(property="foo") //(1)
@Requires(property="foo", value="John") //(2)
@Requires(property="foo", value="John", defaultValue="John") //(3)
@Requires(property="foo", notEquals="Sally") //(4)
  1. Requires the property to be set

  2. Requires the property to be "John"

  3. Requires the property to be "John" or not set

  4. Requires the property to not be "Sally" or not set

Referencing bean properties in @Requires.

You can also reference other beans properties in @Requires to conditionally load beans. Similar to property requirements, you can specify required value or set the value bean property should not be equal to using notEquals annotation member. For the bean property to be checked, the bean of type specified in bean annotation member should be present within context, otherwise conditional bean will not be loaded.

@Requires(bean=Config.class, beanProperty="foo") //(1)
@Requires(bean=Config.class, beanProperty="foo", value="John") //(2)
@Requires(bean=Config.class, beanProperty="foo", notEquals="Sally") //(3)
  1. Requires the "foo" property on Config bean to be set

  2. Requires the "foo" property on Config bean to be "John"

  3. Requires the "foo" property on Config bean to not be "Sally" or not set

Specified bean property is accessed through respective getter method whose presence and availability will be checked at compilation time.

Note that bean property is considered to be present in case it’s value is not null. Keep in mind that primitive properties are initialized with default values such as false for boolean and 0 for int, so they are considered to be set even if no value is explicitly specified for them.

Debugging Conditional Beans

If you have multiple conditions and complex requirements it may become difficult to understand why a particular bean has not been loaded.

To help resolve issues with conditional beans you can enable debug logging for the io.micronaut.context.condition package which will log the reasons why beans were not loaded.

logback.xml
<logger name="io.micronaut.context.condition" level="DEBUG"/>

Consult the logging chapter for details howto setup logging.