Home / Class/ ProjectGenerator Class — spring-boot Architecture

ProjectGenerator Class — spring-boot Architecture

Architecture documentation for the ProjectGenerator class in ProjectGenerator.java from the spring-boot codebase.

Entity Profile

Relationship Graph

Source Code

cli/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/init/ProjectGenerator.java lines 38–164

class ProjectGenerator {

	private static final String ZIP_MIME_TYPE = "application/zip";

	private final InitializrService initializrService;

	ProjectGenerator(InitializrService initializrService) {
		this.initializrService = initializrService;
	}

	void generateProject(ProjectGenerationRequest request, boolean force) throws IOException {
		ProjectGenerationResponse response = this.initializrService.generate(request);
		String fileName = (request.getOutput() != null) ? request.getOutput() : response.getFileName();
		if (shouldExtract(request, response)) {
			if (isZipArchive(response)) {
				extractProject(response, request.getOutput(), force);
				return;
			}
			else {
				Log.info("Could not extract '" + response.getContentType() + "'");
				// Use value from the server since we can't extract it
				fileName = response.getFileName();
			}
		}
		if (fileName == null) {
			throw new ReportableException("Could not save the project, the server did not set a preferred "
					+ "file name and no location was set. Specify the output location for the project.");
		}
		writeProject(response, fileName, force);
	}

	/**
	 * Detect if the project should be extracted.
	 * @param request the generation request
	 * @param response the generation response
	 * @return if the project should be extracted
	 */
	private boolean shouldExtract(ProjectGenerationRequest request, ProjectGenerationResponse response) {
		if (request.isExtract()) {
			return true;
		}
		// explicit name hasn't been provided for an archive and there is no extension
		return isZipArchive(response) && request.getOutput() != null && !request.getOutput().contains(".");
	}

	private boolean isZipArchive(ProjectGenerationResponse entity) {
		if (entity.getContentType() != null) {
			try {
				return ZIP_MIME_TYPE.equals(entity.getContentType().getMimeType());
			}
			catch (Exception ex) {
				// Ignore
			}
		}
		return false;
	}

	private void extractProject(ProjectGenerationResponse entity, @Nullable String output, boolean overwrite)
			throws IOException {
		File outputDirectory = (output != null) ? new File(output) : new File(System.getProperty("user.dir"));
		if (!outputDirectory.exists()) {
			outputDirectory.mkdirs();
		}
		byte[] content = entity.getContent();
		Assert.state(content != null, "'content' must not be null");
		try (ZipInputStream zipStream = new ZipInputStream(new ByteArrayInputStream(content))) {
			extractFromStream(zipStream, overwrite, outputDirectory);
			fixExecutableFlag(outputDirectory, "mvnw");
			fixExecutableFlag(outputDirectory, "gradlew");
			Log.info("Project extracted to '" + outputDirectory.getAbsolutePath() + "'");
		}
	}

	private void extractFromStream(ZipInputStream zipStream, boolean overwrite, File outputDirectory)
			throws IOException {
		ZipEntry entry = zipStream.getNextEntry();
		String canonicalOutputPath = outputDirectory.getCanonicalPath() + File.separator;
		while (entry != null) {
			File file = new File(outputDirectory, entry.getName());
			String canonicalEntryPath = file.getCanonicalPath();
			if (!canonicalEntryPath.startsWith(canonicalOutputPath)) {
				throw new ReportableException("Entry '" + entry.getName() + "' would be written to '"
						+ canonicalEntryPath + "'. This is outside the output location of '" + canonicalOutputPath
						+ "'. Verify your target server configuration.");
			}
			if (file.exists() && !overwrite) {
				throw new ReportableException((file.isDirectory() ? "Directory" : "File") + " '" + file.getName()
						+ "' already exists. Use --force if you want to overwrite or "
						+ "specify an alternate location.");
			}
			if (!entry.isDirectory()) {
				FileCopyUtils.copy(StreamUtils.nonClosing(zipStream), new FileOutputStream(file));
			}
			else {
				file.mkdir();
			}
			zipStream.closeEntry();
			entry = zipStream.getNextEntry();
		}
	}

	private void writeProject(ProjectGenerationResponse entity, String output, boolean overwrite) throws IOException {
		File outputFile = new File(output);
		if (outputFile.exists()) {
			if (!overwrite) {
				throw new ReportableException(
						"File '" + outputFile.getName() + "' already exists. Use --force if you want to "
								+ "overwrite or specify an alternate location.");
			}
			if (!outputFile.delete()) {
				throw new ReportableException("Failed to delete existing file " + outputFile.getPath());
			}
		}
		byte[] content = entity.getContent();
		Assert.state(content != null, "'content' must not be null");
		FileCopyUtils.copy(content, outputFile);
		Log.info("Content saved to '" + output + "'");
	}

	private void fixExecutableFlag(File dir, String fileName) {
		File f = new File(dir, fileName);
		if (f.exists()) {
			f.setExecutable(true, false);
		}
	}

}

Domain

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free