/*
* Copyright 2017-2020 original 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.micronaut.core.naming;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.util.StringUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Arrays;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
Naming convention utilities.
Author: Graeme Rocher Since: 1.0
/**
* <p>Naming convention utilities.</p>
*
* @author Graeme Rocher
* @since 1.0
*/
public class NameUtils {
private static final int PREFIX_LENTGH = 3;
private static final int IS_LENTGH = 2;
private static final Pattern DOT_UPPER = Pattern.compile("\\.[A-Z\\$]");
private static final Pattern SERVICE_ID_REGEX = Pattern.compile("[\\p{javaLowerCase}\\d-]+");
private static final String PREFIX_GET = "get";
private static final String PREFIX_SET = "set";
private static final Pattern ENVIRONMENT_VAR_SEQUENCE = Pattern.compile("^[\\p{Lu}_{0-9}]+");
private static final Pattern KEBAB_CASE_SEQUENCE = Pattern.compile("^(([a-z0-9])+(\\-|\\.|:)?)*([a-z0-9])+$");
private static final Pattern KEBAB_REPLACEMENTS = Pattern.compile("[_ ]");
Checks whether the given name is a valid service identifier.
Params: - name – The name
Returns: True if it is
/**
* Checks whether the given name is a valid service identifier.
*
* @param name The name
* @return True if it is
*/
public static boolean isHyphenatedLowerCase(String name) {
return StringUtils.isNotEmpty(name) && SERVICE_ID_REGEX.matcher(name).matches() && Character.isLetter(name.charAt(0));
}
Converts class name to property name using JavaBean decapitalization.
Params: - name – The class name
- suffixes – The suffix to remove
Returns: The decapitalized name
/**
* Converts class name to property name using JavaBean decapitalization.
*
* @param name The class name
* @param suffixes The suffix to remove
* @return The decapitalized name
*/
public static String decapitalizeWithoutSuffix(String name, String... suffixes) {
String decapitalized = decapitalize(name);
return trimSuffix(decapitalized, suffixes);
}
Trims the given suffixes.
Params: - string – The string to trim
- suffixes – The suffixes
Returns: The trimmed string
/**
* Trims the given suffixes.
*
* @param string The string to trim
* @param suffixes The suffixes
* @return The trimmed string
*/
public static String trimSuffix(String string, String... suffixes) {
if (suffixes != null) {
for (String suffix : suffixes) {
if (string.endsWith(suffix)) {
return string.substring(0, string.length() - suffix.length());
}
}
}
return string;
}
Converts a property name to class name according to the JavaBean convention.
Params: - name – The property name
Returns: The class name
/**
* Converts a property name to class name according to the JavaBean convention.
*
* @param name The property name
* @return The class name
*/
public static String capitalize(String name) {
final String rest = name.substring(1);
// Funky rule so that names like 'pNAME' will still work.
if (Character.isLowerCase(name.charAt(0)) && (rest.length() > 0) && Character.isUpperCase(rest.charAt(0))) {
return name;
}
return name.substring(0, 1).toUpperCase(Locale.ENGLISH) + rest;
}
Converts camel case to hyphenated, lowercase form.
Params: - name – The name
Returns: The hyphenated string
/**
* Converts camel case to hyphenated, lowercase form.
*
* @param name The name
* @return The hyphenated string
*/
public static String hyphenate(String name) {
return hyphenate(name, true);
}
Converts camel case to hyphenated, lowercase form.
Params: - name – The name
- lowerCase – Whether the result should be converted to lower case
Returns: The hyphenated string
/**
* Converts camel case to hyphenated, lowercase form.
*
* @param name The name
* @param lowerCase Whether the result should be converted to lower case
* @return The hyphenated string
*/
public static String hyphenate(String name, boolean lowerCase) {
if (isHyphenatedLowerCase(name)) {
return KEBAB_REPLACEMENTS.matcher(name).replaceAll("-");
} else {
char separatorChar = '-';
return separateCamelCase(KEBAB_REPLACEMENTS.matcher(name).replaceAll("-"), lowerCase, separatorChar);
}
}
Converts hyphenated, lower-case form to camel-case form.
Params: - name – The hyphenated string
Returns: The camel case form
/**
* Converts hyphenated, lower-case form to camel-case form.
*
* @param name The hyphenated string
* @return The camel case form
*/
public static String dehyphenate(String name) {
return Arrays.stream(name.split("-"))
.map(str -> {
if (str.length() > 0 && Character.isLetter(str.charAt(0))) {
return Character.toUpperCase(str.charAt(0)) + str.substring(1);
}
return str;
})
.collect(Collectors.joining(""));
}
Returns the package name for a class represented as string.
Params: - className – The class name
Returns: The package name
/**
* Returns the package name for a class represented as string.
*
* @param className The class name
* @return The package name
*/
public static String getPackageName(String className) {
Matcher matcher = DOT_UPPER.matcher(className);
if (matcher.find()) {
int position = matcher.start();
return className.substring(0, position);
}
return "";
}
Returns the underscore separated version of the given camel case string.
Params: - camelCase – The camel case name
Returns: The underscore separated version
/**
* Returns the underscore separated version of the given camel case string.
*
* @param camelCase The camel case name
* @return The underscore separated version
*/
public static String underscoreSeparate(String camelCase) {
return separateCamelCase(camelCase.replace('-', '_'), false, '_');
}
Returns the underscore separated version of the given camel case string.
Params: - camelCase – The camel case name
Returns: The underscore separated version
/**
* Returns the underscore separated version of the given camel case string.
*
* @param camelCase The camel case name
* @return The underscore separated version
*/
public static String environmentName(String camelCase) {
return separateCamelCase(camelCase.replace('-', '_').replace('.', '_'), false, '_')
.toUpperCase(Locale.ENGLISH);
}
Returns the simple name for a class represented as string.
Params: - className – The class name
Returns: The simple name of the class
/**
* Returns the simple name for a class represented as string.
*
* @param className The class name
* @return The simple name of the class
*/
public static String getSimpleName(String className) {
Matcher matcher = DOT_UPPER.matcher(className);
if (matcher.find()) {
int position = matcher.start();
return className.substring(position + 1);
}
return className;
}
Is the given method name a valid setter name.
Params: - methodName – The method name
Returns: True if it is a valid setter name
/**
* Is the given method name a valid setter name.
*
* @param methodName The method name
* @return True if it is a valid setter name
*/
public static boolean isSetterName(String methodName) {
int len = methodName.length();
if (len > PREFIX_LENTGH && methodName.startsWith(PREFIX_SET)) {
return Character.isUpperCase(methodName.charAt(PREFIX_LENTGH));
}
return false;
}
Get the equivalent property name for the given setter.
Params: - setterName – The setter
Returns: The property name
/**
* Get the equivalent property name for the given setter.
*
* @param setterName The setter
* @return The property name
*/
public static String getPropertyNameForSetter(String setterName) {
if (isSetterName(setterName)) {
return decapitalize(setterName.substring(PREFIX_LENTGH));
}
return setterName;
}
Get the equivalent setter name for the given property.
Params: - propertyName – The property name
Returns: The setter name
/**
* Get the equivalent setter name for the given property.
*
* @param propertyName The property name
* @return The setter name
*/
public static @NonNull String setterNameFor(@NonNull String propertyName) {
ArgumentUtils.requireNonNull("propertyName", propertyName);
return nameFor(PREFIX_SET, propertyName);
}
Is the given method name a valid getter name.
Params: - methodName – The method name
Returns: True if it is a valid getter name
/**
* Is the given method name a valid getter name.
*
* @param methodName The method name
* @return True if it is a valid getter name
*/
public static boolean isGetterName(String methodName) {
int prefixLength = 0;
if (methodName.startsWith(PREFIX_GET)) {
prefixLength = PREFIX_LENTGH;
} else if (methodName.startsWith("is")) {
prefixLength = IS_LENTGH;
} else {
return false;
}
int len = methodName.length();
if (len > prefixLength) {
return Character.isUpperCase(methodName.charAt(prefixLength));
}
return false;
}
Get the equivalent property name for the given getter.
Params: - getterName – The getter
Returns: The property name
/**
* Get the equivalent property name for the given getter.
*
* @param getterName The getter
* @return The property name
*/
public static String getPropertyNameForGetter(String getterName) {
if (isGetterName(getterName)) {
int prefixLength = 0;
if (getterName.startsWith(PREFIX_GET)) {
prefixLength = PREFIX_LENTGH;
}
if (getterName.startsWith("is")) {
prefixLength = IS_LENTGH;
}
return decapitalize(getterName.substring(prefixLength));
}
return getterName;
}
Get the equivalent getter name for the given property.
Params: - propertyName – The property name
Returns: The getter name
/**
* Get the equivalent getter name for the given property.
*
* @param propertyName The property name
* @return The getter name
*/
public static @NonNull String getterNameFor(@NonNull String propertyName) {
ArgumentUtils.requireNonNull("propertyName", propertyName);
return nameFor(PREFIX_GET, propertyName);
}
Get the equivalent getter name for the given property.
Params: - propertyName – The property name
- type – The type of the property
Returns: The getter name
/**
* Get the equivalent getter name for the given property.
*
* @param propertyName The property name
* @param type The type of the property
* @return The getter name
*/
public static @NonNull String getterNameFor(@NonNull String propertyName, @NonNull Class<?> type) {
ArgumentUtils.requireNonNull("propertyName", propertyName);
final boolean isBoolean = type == boolean.class;
return getterNameFor(propertyName, isBoolean);
}
Get the equivalent getter name for the given property.
Params: - propertyName – The property name
- isBoolean – Is the property a boolean
Returns: The getter name
/**
* Get the equivalent getter name for the given property.
*
* @param propertyName The property name
* @param isBoolean Is the property a boolean
* @return The getter name
*/
public static String getterNameFor(@NonNull String propertyName, boolean isBoolean) {
return nameFor(isBoolean ? "is" : PREFIX_GET, propertyName);
}
private static String nameFor(String prefix, @NonNull String propertyName) {
final int len = propertyName.length();
switch (len) {
case 0:
return propertyName;
case 1:
return prefix + propertyName.toUpperCase(Locale.ENGLISH);
default:
return prefix + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
}
}
Decapitalizes a given string according to the rule:
- If the first or only character is Upper Case, it is made Lower Case
- UNLESS the second character is also Upper Case, when the String is
returned unchanged .
Params: - name – The String to decapitalize
Returns: The decapitalized version of the String
/**
* Decapitalizes a given string according to the rule:
* <ul>
* <li>If the first or only character is Upper Case, it is made Lower Case
* <li>UNLESS the second character is also Upper Case, when the String is
* returned unchanged <eul>.
* </ul>
*
* @param name The String to decapitalize
* @return The decapitalized version of the String
*/
public static String decapitalize(String name) {
if (name == null) {
return null;
}
// The rule for decapitalize is that:
// If the first letter of the string is Upper Case, make it lower case
// UNLESS the second letter of the string is also Upper Case, in which case no
// changes are made.
switch (name.length()) {
case 0:
return name;
case 1:
return Character.isUpperCase(name.charAt(0)) ? Character.toString(Character.toLowerCase(name.charAt(0))) : name;
default:
if (!Character.isUpperCase(name.charAt(0)) || Character.isUpperCase(name.charAt(1))) {
return name;
}
char[] chars = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
}
private static String separateCamelCase(String name, boolean lowerCase, char separatorChar) {
if (!lowerCase) {
StringBuilder newName = new StringBuilder();
boolean first = true;
char last = '0';
for (char c : name.toCharArray()) {
if (first) {
newName.append(c);
first = false;
} else {
if (Character.isUpperCase(c) && !Character.isUpperCase(last)) {
if (c != separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
} else {
if (c == '.') {
first = true;
}
if (c != separatorChar) {
if (last == separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
}
}
}
last = c;
}
return newName.toString();
} else {
StringBuilder newName = new StringBuilder();
char[] chars = name.toCharArray();
boolean first = true;
char last = '0';
for (char c : chars) {
if (Character.isLowerCase(c) || !Character.isLetter(c)) {
first = false;
if (c != separatorChar) {
if (last == separatorChar) {
newName.append(separatorChar);
}
newName.append(c);
}
} else {
char lowerCaseChar = Character.toLowerCase(c);
if (first) {
first = false;
newName.append(lowerCaseChar);
} else if (Character.isUpperCase(last) || Character.isDigit(last) || last == '.') {
newName.append(lowerCaseChar);
} else {
newName.append(separatorChar).append(lowerCaseChar);
}
}
last = c;
}
return newName.toString();
}
}
Retrieves the extension of a file name.
Ex: index.html -> html
Params: - filename – The name of the file
Returns: The file extension
/**
* Retrieves the extension of a file name.
* Ex: index.html -> html
*
* @param filename The name of the file
* @return The file extension
*/
public static String extension(String filename) {
int extensionPos = filename.lastIndexOf('.');
int lastUnixPos = filename.lastIndexOf('/');
int lastWindowsPos = filename.lastIndexOf('\\');
int lastSeparator = Math.max(lastUnixPos, lastWindowsPos);
int index = lastSeparator > extensionPos ? -1 : extensionPos;
if (index == -1) {
return "";
}
return filename.substring(index + 1);
}
The camel case version of the string with the first letter in lower case.
Params: - str – The string
Returns: The new string in camel case
/**
* The camel case version of the string with the first letter in lower case.
*
* @param str The string
* @return The new string in camel case
*/
public static String camelCase(String str) {
return camelCase(str, true);
}
The camel case version of the string with the first letter in lower case.
Params: - str – The string
- lowerCaseFirstLetter – Whether the first letter is in upper case or lower case
Returns: The new string in camel case
/**
* The camel case version of the string with the first letter in lower case.
*
* @param str The string
* @param lowerCaseFirstLetter Whether the first letter is in upper case or lower case
* @return The new string in camel case
*/
public static String camelCase(String str, boolean lowerCaseFirstLetter) {
String result = Arrays.stream(str.split("[\\s_-]")).map(NameUtils::capitalize).collect(Collectors.joining(""));
if (lowerCaseFirstLetter) {
return decapitalize(result);
}
return result;
}
Retrieves the fileName of a file without extension.
Ex: index.html -> index
Params: - path – The path of the file
Returns: The file name without extension
/**
* Retrieves the fileName of a file without extension.
* Ex: index.html -> index
*
* @param path The path of the file
* @return The file name without extension
*/
public static String filename(String path) {
int extensionPos = path.lastIndexOf('.');
int lastUnixPos = path.lastIndexOf('/');
int lastWindowsPos = path.lastIndexOf('\\');
int lastSeparator = Math.max(lastUnixPos, lastWindowsPos);
int index = lastSeparator > extensionPos ? path.length() : extensionPos;
if (index == -1) {
return "";
}
return path.substring(lastSeparator + 1, index);
}
Checks whether the string is a valid hyphenated (kebab-case) property name.
Params: - str – The string to check
Returns: Whether is valid kebab-case or not
/**
* Checks whether the string is a valid hyphenated (kebab-case) property name.
*
* @param str The string to check
* @return Whether is valid kebab-case or not
*/
public static boolean isValidHyphenatedPropertyName(String str) {
return KEBAB_CASE_SEQUENCE.matcher(str).matches();
}
Checks whether the string is a valid environment-style property name.
Params: - str – The string to check
Returns: Whether is valid environment-style property name or not
/**
* Checks whether the string is a valid environment-style property name.
*
* @param str The string to check
* @return Whether is valid environment-style property name or not
*/
public static boolean isEnvironmentName(String str) {
return ENVIRONMENT_VAR_SEQUENCE.matcher(str).matches();
}
}