ChangesetAutoConfiguration.java

package com.phactum.mongodb.changesets;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.data.mongodb.autoconfigure.DataMongoRepositoriesAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.mongodb.client.MongoClient;

/**
 * Wires the changeset mechanism into a Spring Boot application.
 * <p>
 * The beans it publishes are the configuration of the mechanism and the {@link ChangesetApplier},
 * which does the work while the application starts. The applier is created before the MongoDB
 * repositories are, so no repository is used on a database which has not been migrated yet.
 * <p>
 * An application which holds the MongoDB mode somewhere else already can publish a
 * {@link ChangesetProperties} bean of its own. Then the key <code>mongodb.changesets.mode</code>
 * is not needed, because the bean of the application is used instead of the one created here.
 * <p>
 * Do not inject this class to wait for the migration. A configuration class is built before the
 * beans it declares, so this one exists long before the applier has run. Such an injection
 * compiles, the application starts, and the order is quietly gone. Inject
 * {@link ChangesetApplier} instead.
 *
 * @see ChangesetApplier
 * @see DbChangeset
 * @see DbChangesetConfiguration
 */
// registered through the .imports file, so it has to be an @AutoConfiguration. Only then are
// @AutoConfigureBefore and @AutoConfigureAfter read
@AutoConfiguration
@AutoConfigureBefore(DataMongoRepositoriesAutoConfiguration.class)
@ConditionalOnClass({
    MongoClient.class, MongoTemplate.class
})
// No class is named here. This only asks Spring Boot for the machinery which binds a bean whose
// class carries @ConfigurationProperties. Naming ChangesetProperties would publish a second bean
// of that class beside the one below, and then nothing could be injected by type any more.
@EnableConfigurationProperties
public class ChangesetAutoConfiguration {

  @Bean
  @ConditionalOnMissingBean
  public ChangesetProperties mongoDbChangesetProperties() {

    return new ChangesetProperties();

  }

  @Bean
  public ChangesetApplier mongoDbChangesetApplier(
      final ApplicationContext applicationContext,
      final MongoTemplate mongoTemplate,
      final ChangesetProperties properties) {

    return new ChangesetApplier(applicationContext, mongoTemplate, properties);

  }

}