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

org.springframework.aot.generate.ClassNameGenerator 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.aot.generate;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.javapoet.ClassName;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

/**
 * Generate unique class names based on a target {@link ClassName} and a
 * feature name.
 *
 * 

This class is stateful, so the same instance should be used for all name * generation. * * @author Phillip Webb * @author Stephane Nicoll * @since 6.0 */ public final class ClassNameGenerator { private static final String SEPARATOR = "__"; private static final String AOT_FEATURE = "Aot"; private final ClassName defaultTarget; private final String featureNamePrefix; private final Map sequenceGenerator; /** * Create a new instance using the specified {@code defaultTarget} and no * feature name prefix. * @param defaultTarget the default target class to use */ public ClassNameGenerator(ClassName defaultTarget) { this(defaultTarget, ""); } /** * Create a new instance using the specified {@code defaultTarget} and * feature name prefix. * @param defaultTarget the default target class to use * @param featureNamePrefix the prefix to use to qualify feature names */ public ClassNameGenerator(ClassName defaultTarget, String featureNamePrefix) { this(defaultTarget, featureNamePrefix, new ConcurrentHashMap<>()); } private ClassNameGenerator(ClassName defaultTarget, String featureNamePrefix, Map sequenceGenerator) { Assert.notNull(defaultTarget, "'defaultTarget' must not be null"); this.defaultTarget = defaultTarget; this.featureNamePrefix = (!StringUtils.hasText(featureNamePrefix) ? "" : featureNamePrefix); this.sequenceGenerator = sequenceGenerator; } String getFeatureNamePrefix() { return this.featureNamePrefix; } /** * Generate a unique {@link ClassName} based on the specified * {@code featureName} and {@code target}. If the {@code target} is * {@code null}, the configured main target of this instance is used. *

The class name is a suffixed version of the target. For instance, a * {@code com.example.Demo} target with an {@code Initializer} feature name * leads to a {@code com.example.Demo__Initializer} generated class name. * The feature name is qualified by the configured feature name prefix, * if any. *

Generated class names are unique. If such a feature was already * requested for this target, a counter is used to ensure uniqueness. * @param featureName the name of the feature that the generated class * supports * @param target the class the newly generated class relates to, or * {@code null} to use the main target * @return a unique generated class name */ public ClassName generateClassName(String featureName, @Nullable ClassName target) { return generateSequencedClassName(getRootName(featureName, target)); } private String getRootName(String featureName, @Nullable ClassName target) { Assert.hasLength(featureName, "'featureName' must not be empty"); featureName = clean(featureName); ClassName targetToUse = (target != null ? target : this.defaultTarget); String featureNameToUse = this.featureNamePrefix + featureName; return toName(targetToUse).replace("$", "_") + SEPARATOR + StringUtils.capitalize(featureNameToUse); } private String clean(String name) { StringBuilder clean = new StringBuilder(); boolean lastNotLetter = true; for (char ch : name.toCharArray()) { if (!Character.isLetter(ch)) { lastNotLetter = true; continue; } clean.append(lastNotLetter ? Character.toUpperCase(ch) : ch); lastNotLetter = false; } return (!clean.isEmpty()) ? clean.toString() : AOT_FEATURE; } private ClassName generateSequencedClassName(String name) { int sequence = this.sequenceGenerator.computeIfAbsent(name, key -> new AtomicInteger()).getAndIncrement(); if (sequence > 0) { name = name + sequence; } return ClassName.get(ClassUtils.getPackageName(name), ClassUtils.getShortName(name)); } /** * Create a new {@link ClassNameGenerator} instance for the specified * feature name prefix, keeping track of all the class names generated * by this instance. * @param featureNamePrefix the feature name prefix to use * @return a new instance for the specified feature name prefix */ ClassNameGenerator withFeatureNamePrefix(String featureNamePrefix) { return new ClassNameGenerator(this.defaultTarget, featureNamePrefix, this.sequenceGenerator); } private static String toName(ClassName className) { return GeneratedTypeReference.of(className).getName(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy