All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.spring.initializr.generator.project.ProjectGenerator Maven / Gradle / Ivy

There is a newer version: 0.21.0
Show newest version
/*
 * Copyright 2012-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.spring.initializr.generator.project;

import java.io.IOException;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.io.support.SpringFactoriesLoader;

/**
 * Main entry point for project generation that processes a {@link ProjectDescription} by
 * creating a dedicated {@link ProjectGenerationContext} with all available
 * {@link ProjectGenerationConfiguration} classes. Once the context has been started for a
 * particular {@link ProjectDescription}, a {@link ProjectAssetGenerator} can query it and
 * generate an appropriate asset (for instance, a project structure on disk).
 *
 * @author Andy Wilkinson
 * @author Stephane Nicoll
 */
public class ProjectGenerator {

	private final Consumer contextConsumer;

	private final Supplier contextFactory;

	/**
	 * Create an instance with a customizer for the project generator application context
	 * and a factory for the {@link ProjectGenerationContext}.
	 * @param contextConsumer a consumer of the project generation context after
	 * contributors and the {@link ProjectDescription} have been registered but before it
	 * is refreshed
	 * @param contextFactory the factory to use to create {@link ProjectGenerationContext}
	 * instances
	 */
	public ProjectGenerator(Consumer contextConsumer,
			Supplier contextFactory) {
		this.contextConsumer = contextConsumer;
		this.contextFactory = contextFactory;
	}

	/**
	 * Create an instance with a customizer for the {@link ProjectGenerationContext} and a
	 * default factory for the {@link ProjectGenerationContext} that disables bean
	 * definition overriding.
	 * @param contextConsumer a consumer of the project generation context after
	 * contributors and the {@link ProjectDescription} have been registered but before it
	 * is refreshed
	 * @see GenericApplicationContext#setAllowBeanDefinitionOverriding(boolean)
	 */
	public ProjectGenerator(Consumer contextConsumer) {
		this(contextConsumer, defaultContextFactory());
	}

	private static Supplier defaultContextFactory() {
		return () -> {
			ProjectGenerationContext context = new ProjectGenerationContext();
			context.setAllowBeanDefinitionOverriding(false);
			return context;
		};
	}

	/**
	 * Generate project assets using the specified {@link ProjectAssetGenerator} for the
	 * specified {@link ProjectDescription}.
	 * 

* Create a dedicated {@link ProjectGenerationContext} using the supplied * {@link #ProjectGenerator(Consumer, Supplier) contextFactory} and then apply the * following: *

    *
  • Register a {@link ProjectDescription} bean based on the given * {@code description} post-processed by available * {@link ProjectDescriptionCustomizer} beans.
  • *
  • Process all registered {@link ProjectGenerationConfiguration} classes.
  • *
  • Apply the {@link #ProjectGenerator(Consumer, Supplier) contextConsumer} to * further customize the context before it is refreshed.
  • *
* @param description the description of the project to generate * @param projectAssetGenerator the {@link ProjectAssetGenerator} to invoke * @param the type that gathers the project assets * @return the generated content * @throws ProjectGenerationException if an error occurs while generating the project */ public T generate(ProjectDescription description, ProjectAssetGenerator projectAssetGenerator) throws ProjectGenerationException { try (ProjectGenerationContext context = this.contextFactory.get()) { registerProjectDescription(context, description); registerProjectContributors(context, description); this.contextConsumer.accept(context); context.refresh(); try { return projectAssetGenerator.generate(context); } catch (IOException ex) { throw new ProjectGenerationException("Failed to generate project", ex); } } } /** * Return the {@link ProjectGenerationConfiguration} class names that should be * considered. By default this method will load candidates using * {@link SpringFactoriesLoader} with {@link ProjectGenerationConfiguration}. * @param description the description of the project to generate * @return a list of candidate configurations */ protected List getCandidateProjectGenerationConfigurations(ProjectDescription description) { return SpringFactoriesLoader.loadFactoryNames(ProjectGenerationConfiguration.class, getClass().getClassLoader()); } private void registerProjectDescription(ProjectGenerationContext context, ProjectDescription description) { context.registerBean(ProjectDescription.class, resolve(description, context)); } private void registerProjectContributors(ProjectGenerationContext context, ProjectDescription description) { getCandidateProjectGenerationConfigurations(description).forEach((configurationClassName) -> { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClassName(configurationClassName); context.registerBeanDefinition(configurationClassName, beanDefinition); }); } private Supplier resolve(ProjectDescription description, ProjectGenerationContext context) { return () -> { if (description instanceof MutableProjectDescription) { MutableProjectDescription mutableDescription = (MutableProjectDescription) description; ProjectDescriptionDiffFactory diffFactory = context.getBeanProvider(ProjectDescriptionDiffFactory.class) .getIfAvailable(DefaultProjectDescriptionDiffFactory::new); // Create the diff here so that it takes a copy of the description // immediately ProjectDescriptionDiff diff = diffFactory.create(mutableDescription); context.registerBean(ProjectDescriptionDiff.class, () -> diff); context.getBeanProvider(ProjectDescriptionCustomizer.class).orderedStream() .forEach((customizer) -> customizer.customize(mutableDescription)); } return description; }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy