io.avaje.prism.internal.UtilWriter Maven / Gradle / Ivy
The newest version!
package io.avaje.prism.internal;
import java.io.PrintWriter;
public class UtilWriter {
private UtilWriter() {}
public static void write(PrintWriter out, String packageName) {
out.append(
"package "
+ packageName
+ ";\n"
+ "\n"
+ "\n"
+ "import java.util.Map;\n"
+ "import java.util.regex.Matcher;\n"
+ "import java.util.regex.Pattern;\n"
+ "\n"
+ "import javax.annotation.processing.Generated;\n"
+ "import javax.lang.model.element.Element;\n"
+ "import javax.lang.model.element.VariableElement;\n"
+ "\n"
+ "@Generated(\"avaje-prism-generator\")\n"
+ "public final class ProcessorUtils {\n"
+ "\n"
+ " private static final Pattern WHITE_SPACE_REGEX =\n"
+ " Pattern.compile(\"\\\\s+(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)\");\n"
+ " private static final Pattern COMMA_PATTERN =\n"
+ " Pattern.compile(\", (?=(?:[^\\\\\\\"]*\\\\\\\"[^\\\\\\\"]*\\\\\\\")*[^\\\\\\\"]*$)\");\n"
+ " private static final Pattern PARENTHESIS_CONTENT = Pattern.compile(\"\\\\((.*?)\\\\)\");\n"
+ "\n"
+ " private ProcessorUtils() {}\n"
+ "\n"
+ " private static final Map BOX_MAP =\n"
+ " Map.of(\n"
+ " \"char\", \"Character\",\n"
+ " \"byte\", \"Byte\",\n"
+ " \"int\", \"Integer\",\n"
+ " \"long\", \"Long\",\n"
+ " \"short\", \"Short\",\n"
+ " \"double\", \"Double\",\n"
+ " \"float\", \"Float\",\n"
+ " \"boolean\", \"Boolean\");\n"
+ "\n"
+ " /**\n"
+ " * Returns boxed type if type string is primitive, otherwise return the input unchanged\n"
+ " *\n"
+ " * @param type type string\n"
+ " * @return boxed type string if type is primitive\n"
+ " */\n"
+ " public static String boxedPrimitive(String type) {\n"
+ " final var wrapped = BOX_MAP.get(type);\n"
+ " return wrapped != null ? \"java.lang.\" + wrapped : null;\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Return true if type string is of a primitive type\n"
+ " *\n"
+ " * @param type\n"
+ " * @return true if type represents a primitive\n"
+ " */\n"
+ " public static boolean isPrimitive(String type) {\n"
+ " return BOX_MAP.containsKey(type);\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Get Package from a given fqn string\n"
+ " *\n"
+ " * @param fqn the fully qualified type string\n"
+ " * @return the package of the type\n"
+ " */\n"
+ " public static String packageOf(String fqn) {\n"
+ "\n"
+ " return fqn.replace(\".\" + shortType(fqn), \"\");\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Get short type from a given fqn string. Nested Classes will have parent classes as part of the\n"
+ " * short name\n"
+ " *\n"
+ " * @param fqn the fully qualified type string\n"
+ " * @return the short type\n"
+ " */\n"
+ " public static String shortType(String fqn) {\n"
+ " final int p = fqn.lastIndexOf('.');\n"
+ " if (p == -1) {\n"
+ " return fqn;\n"
+ " }\n"
+ " var result = \"\";\n"
+ " var foundClass = false;\n"
+ " for (final String part : fqn.split(\"\\\\.\")) {\n"
+ " char firstChar = part.charAt(0);\n"
+ " if (foundClass\n"
+ " || Character.isUpperCase(firstChar)\n"
+ " || (!Character.isAlphabetic(firstChar) && Character.isJavaIdentifierStart(firstChar))) {\n"
+ " foundClass = true;\n"
+ " result += (result.isEmpty() ? \"\" : \".\") + part;\n"
+ " }\n"
+ " }\n"
+ " // when in doubt, do the basic thing\n"
+ " if (result.isBlank()) {\n"
+ " return fqn.substring(p + 1);\n"
+ " }\n"
+ " return result;\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Remove all annotations and their values from a string.\n"
+ " *\n"
+ " * @param input string to remove annotations from\n"
+ " * @return input free of annotations\n"
+ " */\n"
+ " public static String trimAnnotations(String input) {\n"
+ " input = COMMA_PATTERN.matcher(input).replaceAll(\",\");\n"
+ " return cutAnnotations(input);\n"
+ " }\n"
+ "\n"
+ " private static String cutAnnotations(String input) {\n"
+ " final int pos = input.indexOf(\"@\");\n"
+ " if (pos == -1) {\n"
+ " return input;\n"
+ " }\n"
+ "\n"
+ " final Matcher matcher = WHITE_SPACE_REGEX.matcher(input);\n"
+ "\n"
+ " int currentIndex = 0;\n"
+ " if (matcher.find()) {\n"
+ " currentIndex = matcher.start();\n"
+ " }\n"
+ " final var result = input.substring(0, pos) + input.substring(currentIndex + 1);\n"
+ " return cutAnnotations(result);\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Return the common parent package between two classes/packages.\n"
+ " *\n"
+ " * @param firstPkg first class/package string\n"
+ " * @param secondPkg second class/package string\n"
+ " * @return the common package between the two classes\n"
+ " */\n"
+ " public static String commonParent(String firstPkg, String secondPkg) {\n"
+ " if (secondPkg == null) return firstPkg;\n"
+ " if (firstPkg == null) return packageOf(secondPkg);\n"
+ " if (secondPkg.startsWith(firstPkg)) {\n"
+ " return firstPkg;\n"
+ " }\n"
+ " int next;\n"
+ " do {\n"
+ " next = firstPkg.lastIndexOf('.');\n"
+ " if (next > -1) {\n"
+ " firstPkg = firstPkg.substring(0, next);\n"
+ " if (secondPkg.startsWith(firstPkg)) {\n"
+ " return firstPkg;\n"
+ " }\n"
+ " }\n"
+ " } while (next > -1);\n"
+ "\n"
+ " return firstPkg;\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Determine if a VariableElement is a varargs parameter\n"
+ " *\n"
+ " * @param element the parameter element\n"
+ " * @param position the position of the parameter in the signature\n"
+ " * @return true if element is a varargs parameter, false otherwise\n"
+ " */\n"
+ " public static boolean isVarArg(VariableElement element, int position) {\n"
+ " final var methodString = trimAnnotations(element.getEnclosingElement().toString());\n"
+ " final var typeString = trimAnnotations(element.asType().toString()).replace(\"[]\", \"\");\n"
+ " final Matcher matcher = PARENTHESIS_CONTENT.matcher(methodString);\n"
+ "\n"
+ " if (matcher.find()) {\n"
+ " final var param = matcher.group(1).split(\",\")[position];\n"
+ "\n"
+ " return param.replace(\"[]\", \"\").contains(typeString) && param.endsWith(\"...\");\n"
+ " }\n"
+ " return false;\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Check if element has an annotation with a simple name that matches the given short name\n"
+ " *\n"
+ " * @param element element to check\n"
+ " * @param simpleName the simple name of the target annotation\n"
+ " * @return true if a matching annotation is present\n"
+ " */\n"
+ " public static boolean hasAnnotationWithName(Element element, String simpleName) {\n"
+ " for (final var mirror : element.getAnnotationMirrors()) {\n"
+ " if (simpleName.equals(mirror.getAnnotationType().asElement().getSimpleName().toString())) {\n"
+ " return true;\n"
+ " }\n"
+ " }\n"
+ " return false;\n"
+ " }\n"
+ "\n"
+ " /**\n"
+ " * Sanitize an import string to remove invalid characters\n"
+ " *\n"
+ " * @param input input to sanitize\n"
+ " * @return sanitized import statement\n"
+ " */\n"
+ " public static String sanitizeImports(String input) {\n"
+ " final int pos = input.indexOf(\"@\");\n"
+ " if (pos == -1) {\n"
+ " return removeInvalidChars(input);\n"
+ " }\n"
+ " final var start = pos == 0 ? input.substring(0, pos) : \"\";\n"
+ " return start + removeInvalidChars(input.substring(input.lastIndexOf(' ') + 1));\n"
+ " }\n"
+ "\n"
+ " private static String removeInvalidChars(String type) {\n"
+ " return type.replaceAll(\"[^\\\\n\\\\r\\\\t $;\\\\w.]\", \"\");\n"
+ " }\n"
+ " /**\n"
+ " * Get the enclosed type from a nested class, or return the type itself if not nested. (i.e.\n"
+ " * {@code io.package.Top.Nested} will become {@code io.package.Top})\n"
+ " *\n"
+ " * @param fqn fully qualified type to extract\n"
+ " * @return sanitized import statement\n"
+ " */\n"
+ " public static String extractEnclosingFQN(String fqn) {\n"
+ " int p = fqn.lastIndexOf('.');\n"
+ " if (p == -1) {\n"
+ " return fqn;\n"
+ " }\n"
+ " final StringBuilder result = new StringBuilder();\n"
+ " var foundClass = false;\n"
+ " var firstClass = true;\n"
+ " for (final String part : fqn.split(\"\\\\.\")) {\n"
+ " if (Character.isUpperCase(part.charAt(0))) {\n"
+ " foundClass = true;\n"
+ " }\n"
+ " result.append(foundClass && !firstClass ? \"/\" : \".\").append(part);\n"
+ " if (foundClass) {\n"
+ " firstClass = false;\n"
+ " }\n"
+ " }\n"
+ " if (result.charAt(0) == '.') {\n"
+ " result.deleteCharAt(0);\n"
+ " }\n"
+ " final var fullResult = result.toString();\n"
+ "\n"
+ " p = fullResult.lastIndexOf('/');\n"
+ " if (p == -1) {\n"
+ " return fullResult;\n"
+ " }\n"
+ " return fullResult.substring(0, p);\n"
+ " }\n"
+ "}\n");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy