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

io.ultreia.java4all.i18n.spi.builder.TranslateEnumerationProcessor Maven / Gradle / Ivy

The newest version!
package io.ultreia.java4all.i18n.spi.builder;

/*-
 * #%L
 * I18n :: Spi Builder
 * %%
 * Copyright (C) 2018 - 2024 Code Lutin, Ultreia.io
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.auto.service.AutoService;
import io.ultreia.java4all.i18n.spi.enumeration.TranslateEnumeration;
import io.ultreia.java4all.i18n.spi.enumeration.TranslateEnumerations;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;

/**
 * To generate translate enumeration helper.
 * 

* Created on 06/09/2021. * * @author Tony Chemit - [email protected] * @since 3.0.0 */ @SupportedAnnotationTypes({"io.ultreia.java4all.i18n.spi.enumeration.TranslateEnumeration", "io.ultreia.java4all.i18n.spi.enumeration.TranslateEnumerations"}) @AutoService(Processor.class) @SupportedOptions({"debug"}) public class TranslateEnumerationProcessor extends AbstractProcessor { @Override public SourceVersion getSupportedSourceVersion() { return SourceVersion.latest(); } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { I18nModule i18nModule; I18nKeySet i18nKeysFile; try { Path configurationPath = Path.of(processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", "fake") .toUri().toURL().getFile()).getParent().getParent().getParent().resolve(".mvn").resolve("i18n-configuration.properties"); if (!Files.exists(configurationPath)) { throw new IllegalStateException("Can't find i18n module configuration at " + configurationPath + ", please launch once i18n:init mojo."); } String i18nModuleConfiguration = Files.readString(configurationPath); Properties properties = new Properties(); properties.put(I18nModuleConfiguration.I18N_MODULE_CONFIGURATION, i18nModuleConfiguration); i18nModule = I18nModule.forGetter(properties); i18nKeysFile = i18nModule.getModuleKeySet("java-enumeration"); } catch (Exception e) { throw new RuntimeException("Can't load I18n module", e); } TypeMirror translateEnumerationType = processingEnv.getElementUtils().getTypeElement(TranslateEnumeration.class.getName()).asType(); TypeMirror translateEnumerationsType = processingEnv.getElementUtils().getTypeElement(TranslateEnumerations.class.getName()).asType(); for (TypeElement annotation : annotations) { Set annotatedElements = roundEnv.getElementsAnnotatedWith(annotation); for (Element annotatedElement : annotatedElements) { EnumerationDefinition definition = new EnumerationDefinition(annotatedElement); List annotationMirrors = processingEnv.getElementUtils().getAllAnnotationMirrors(annotatedElement); TypeMirror annotationType = annotation.asType(); AnnotationMirror annotationMirror = annotationMirrors.stream().filter(a -> a.getAnnotationType().equals(annotationType)).findFirst().orElseThrow(); if (translateEnumerationType.equals(annotationType)) { // single translation definition.addTranslation(annotationMirror); } else if (translateEnumerationsType.equals(annotationType)) { // multiple translations AnnotationValue value = annotationMirror.getElementValues().entrySet().iterator().next().getValue(); List value1 = (List) value.getValue(); for (Object o : value1) { definition.addTranslation((AnnotationMirror) o); } } processEnumeration(definition, i18nKeysFile); } } if (i18nKeysFile.isNotEmpty()) { try { i18nModule.storeModuleKeySet(i18nKeysFile); } catch (IOException e) { throw new RuntimeException("Can't store I18n getters", e); } } return true; } private void processEnumeration(EnumerationDefinition definition, I18nKeySet i18nKeysFile) { String generatedSimpleClassName = definition.enumerationName + "I18n"; String generatedClassName = definition.packageName + "." + generatedSimpleClassName; try { FileObject resource = processingEnv.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, definition.packageName, generatedSimpleClassName + ".java"); Path javaFile = Path.of(resource.toUri().toURL().getFile()); if (Files.exists(javaFile)) { // Already done logWarning(String.format("Skip already processed class: %s", generatedClassName)); return; } } catch (IOException e) { // file not found, can safely execute it } logDebug(String.format("Detect enumeration to process: %s", generatedClassName)); logInfo(String.format("Generate enumeration I18n helper: %s", generatedClassName)); try { JavaFileObject builderFile = processingEnv.getFiler().createSourceFile(generatedClassName); try (BufferedWriter out = new BufferedWriter(new PrintWriter(builderFile.openWriter()))) { generateDefinitionFile(definition, i18nKeysFile, generatedSimpleClassName, out); out.flush(); } } catch (Exception e) { throw new RuntimeException(String.format("Can't generate enumeration I18n file for: %s", generatedClassName), e); } } private void generateDefinitionFile(EnumerationDefinition definition, I18nKeySet i18nKeysFile, String generatedClassName, BufferedWriter writer) throws IOException { String packageName = definition.packageName; String enumerationName = definition.enumerationName; String anEnumType = packageName + "." + enumerationName; writer.write("package " + packageName + ";\n"); writer.write("\n"); writer.write("import javax.annotation.Generated;\n"); writer.write("import java.util.Locale;\n"); writer.newLine(); writer.write("import static io.ultreia.java4all.i18n.I18n.l;\n"); writer.write("import static io.ultreia.java4all.i18n.I18n.t;\n"); writer.newLine(); writer.newLine(); writer.write("@Generated(value = \"Generated by " + getClass().getName() + "\",date = \"" + new Date() + "\")\n"); writer.write("public class " + generatedClassName + " {\n"); writer.newLine(); for (Map.Entry entry : definition.translations.entrySet()) { String name = entry.getKey(); String pattern = entry.getValue(); int ordinal = 0; for (String enumName : definition.enumerationValues) { i18nKeysFile.addKey(definition.transformToKey(pattern, anEnumType, enumerationName, enumName, (ordinal++) + "")); } String methodName = "get" + StringUtils.capitalize(name); writer.write(" protected static String " + methodName + "Key(" + enumerationName + " e) {\n"); writer.write(" return " + definition.transformToMessage(packageName, enumerationName, pattern) + ";\n"); writer.write(" }\n"); writer.newLine(); writer.write(" public static String " + methodName + "(" + enumerationName + " e) {\n"); writer.write(" return t(" + methodName + "Key(e));\n"); writer.write(" }\n"); writer.newLine(); writer.write(" public static String " + methodName + "(Locale locale, " + enumerationName + " e) {\n"); writer.write(" return l(locale, " + methodName + "Key(e));\n"); writer.write(" }\n"); writer.newLine(); } writer.write("}\n"); } private void logDebug(String msg) { if (processingEnv.getOptions().containsKey("debug")) { processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg); } } private void logInfo(String msg) { processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, msg); } private void logWarning(String msg) { processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, msg); } class EnumerationDefinition { final String packageName; final String enumerationName; final Map translations; final Set enumerationValues; public EnumerationDefinition(Element annotatedElement) { TypeElement classElement = (TypeElement) annotatedElement; this.packageName = processingEnv.getElementUtils().getPackageOf(classElement).toString(); this.enumerationName = classElement.getSimpleName().toString(); this.translations = new LinkedHashMap<>(); this.enumerationValues = new LinkedHashSet<>(); processingEnv.getElementUtils().getAllMembers(classElement).stream().filter(m -> m.asType().equals(annotatedElement.asType())).forEach(m -> enumerationValues.add(m.getSimpleName().toString())); } void addTranslation(AnnotationMirror annotationMirror) { Map map = processingEnv.getElementUtils().getElementValuesWithDefaults(annotationMirror); String name = null; String pattern = null; for (Map.Entry entry : map.entrySet()) { String key = entry.getKey().getSimpleName().toString(); switch (key) { case "name": name = entry.getValue().getValue().toString(); break; case "pattern": pattern = entry.getValue().getValue().toString(); break; } } translations.put(name, pattern); } String transformToMessage(String packageName, String enumerationName, String pattern) { StringBuilder builder = new StringBuilder(); StringTokenizer stringTokenizer = new StringTokenizer(pattern, "@"); while (stringTokenizer.hasMoreTokens()) { if (builder.length() > 0) { builder.append(" + "); } String token = stringTokenizer.nextToken(); switch (token) { case "CLASS_SIMPLE_NAME": builder.append(String.format("\"%s\"", enumerationName)); break; case "CLASS_NAME": builder.append(String.format("\"%s.%s\"", packageName, enumerationName)); break; case "NAME": builder.append("e.name()"); break; case "ORDINAL": builder.append("e.ordinal()"); break; default: builder.append(String.format("\"%s\"", token)); } } String result = builder.toString().trim(); if (result.endsWith("+")) { result = result.substring(0, builder.length() - 1); } return result.trim().replaceAll("\" \\+ \"", ""); } String transformToKey(String pattern, String className, String simpleName, String name, String ordinal) { String result = pattern; result = result.replace("@CLASS_NAME@", className); result = result.replace("@CLASS_SIMPLE_NAME@", simpleName); result = result.replace("@NAME@", name); result = result.replace("@ORDINAL@", ordinal); return result; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy