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

org.springframework.context.aot.ContextAotProcessor Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2022 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 org.springframework.context.aot;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.aot.generate.ClassNameGenerator;
import org.springframework.aot.generate.DefaultGenerationContext;
import org.springframework.aot.generate.FileSystemGeneratedFiles;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.javapoet.ClassName;
import org.springframework.util.CollectionUtils;

/**
 * Filesystem-based ahead-of-time (AOT) processing base implementation.
 *
 * 

Concrete implementations are typically used to kick off optimization of an * application in a build tool. * * @author Stephane Nicoll * @author Andy Wilkinson * @author Phillip Webb * @author Sam Brannen * @since 6.0 * @see org.springframework.test.context.aot.TestAotProcessor */ public abstract class ContextAotProcessor extends AbstractAotProcessor { private final Class applicationClass; /** * Create a new processor for the specified application entry point and * common settings. * @param applicationClass the application entry point (class with a {@code main()} method) * @param settings the settings to apply */ protected ContextAotProcessor(Class applicationClass, Settings settings) { super(settings); this.applicationClass = applicationClass; } /** * Get the application entry point (typically a class with a {@code main()} method). */ protected Class getApplicationClass() { return this.applicationClass; } /** * Invoke the processing by clearing output directories first, followed by * {@link #performAotProcessing(GenericApplicationContext)}. * @return the {@code ClassName} of the {@code ApplicationContextInitializer} * entry point */ @Override protected ClassName doProcess() { deleteExistingOutput(); GenericApplicationContext applicationContext = prepareApplicationContext(getApplicationClass()); return performAotProcessing(applicationContext); } /** * Prepare the {@link GenericApplicationContext} for the specified * application entry point to be used against an {@link ApplicationContextAotGenerator}. * @return a non-refreshed {@link GenericApplicationContext} */ protected abstract GenericApplicationContext prepareApplicationContext(Class applicationClass); /** * Perform ahead-of-time processing of the specified context. *

Code, resources, and generated classes are stored in the configured * output directories. In addition, run-time hints are registered for the * application and its entry point. * @param applicationContext the context to process */ protected ClassName performAotProcessing(GenericApplicationContext applicationContext) { FileSystemGeneratedFiles generatedFiles = createFileSystemGeneratedFiles(); DefaultGenerationContext generationContext = new DefaultGenerationContext( createClassNameGenerator(), generatedFiles); ApplicationContextAotGenerator generator = new ApplicationContextAotGenerator(); ClassName generatedInitializerClassName = generator.processAheadOfTime(applicationContext, generationContext); registerEntryPointHint(generationContext, generatedInitializerClassName); generationContext.writeGeneratedContent(); writeHints(generationContext.getRuntimeHints()); writeNativeImageProperties(getDefaultNativeImageArguments(getApplicationClass().getName())); return generatedInitializerClassName; } /** * Callback to customize the {@link ClassNameGenerator}. *

By default, a standard {@link ClassNameGenerator} using the configured * {@linkplain #getApplicationClass() application entry point} as the default * target is used. * @return the class name generator */ protected ClassNameGenerator createClassNameGenerator() { return new ClassNameGenerator(ClassName.get(getApplicationClass())); } /** * Return the native image arguments to use. *

By default, the main class to use, as well as standard application flags * are added. *

If the returned list is empty, no {@code native-image.properties} is * contributed. * @param applicationClassName the fully qualified class name of the application * entry point * @return the native image options to contribute */ protected List getDefaultNativeImageArguments(String applicationClassName) { List args = new ArrayList<>(); args.add("-H:Class=" + applicationClassName); args.add("--report-unsupported-elements-at-runtime"); args.add("--no-fallback"); args.add("--install-exit-handlers"); return args; } private void registerEntryPointHint(DefaultGenerationContext generationContext, ClassName generatedInitializerClassName) { TypeReference generatedType = TypeReference.of(generatedInitializerClassName.canonicalName()); TypeReference applicationType = TypeReference.of(getApplicationClass()); ReflectionHints reflection = generationContext.getRuntimeHints().reflection(); reflection.registerType(applicationType); reflection.registerType(generatedType, typeHint -> typeHint.onReachableType(applicationType) .withConstructor(Collections.emptyList(), ExecutableMode.INVOKE)); } private void writeNativeImageProperties(List args) { if (CollectionUtils.isEmpty(args)) { return; } StringBuilder sb = new StringBuilder(); sb.append("Args = "); sb.append(String.join(String.format(" \\%n"), args)); Path file = getSettings().getResourceOutput().resolve("META-INF/native-image/" + getSettings().getGroupId() + "/" + getSettings().getArtifactId() + "/native-image.properties"); try { if (!Files.exists(file)) { Files.createDirectories(file.getParent()); Files.createFile(file); } Files.writeString(file, sb.toString()); } catch (IOException ex) { throw new IllegalStateException("Failed to write native-image.properties", ex); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy