org.nuiton.i18n.plugin.GenerateI18nEnumHelperMojo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of i18n-maven-plugin Show documentation
Show all versions of i18n-maven-plugin Show documentation
Maven plugin to deal with i18n stuff in a project, mainly base on the
nuiton-i18n api (but not only).
package org.nuiton.i18n.plugin;
/*
* #%L
* I18n :: Maven Plugin
* %%
* Copyright (C) 2007 - 2016 CodeLutin
* %%
* 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.common.base.Charsets;
import com.google.common.io.Files;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.TokenStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.codehaus.plexus.util.StringUtils;
import org.nuiton.i18n.plugin.parser.java.Java8BaseVisitor;
import org.nuiton.i18n.plugin.parser.java.Java8Lexer;
import org.nuiton.i18n.plugin.parser.java.Java8Parser;
import org.nuiton.plugin.PluginHelper;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.TreeSet;
/**
* Generate a i18n enum class helper.
*
* Created on 28/08/16.
*
* @author Tony Chemit - [email protected]
* @since 3.6
*/
@Mojo(name = "generateI18nEnumHelper", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class GenerateI18nEnumHelperMojo extends AbstractI18nMojo {
/**
* To set the package fully qualified name of the generated class.
*
* By default, will use groupId.artifactId (with {@code -} replaced by {@code .}).
*/
@Parameter(property = "i18n.packageName")
private String packageName;
/**
* Name of the generated class.
*/
@Parameter(property = "i18n.className", defaultValue = "I18nEnumHelper", required = true)
private String className;
/**
* The root directory where to generated.
*/
@Parameter(property = "i18n.outputdirectory", defaultValue = "${basedir}/target/generated-sources/java", required = true)
private File outputdirectory;
/**
* List of enumerations set to scan to generate i18n keys.
*
*
* <enumerationSets>
* <enumerationSet>
* <name>label</name>
* <pattern>myPrefix.@CLASS_NAME@.@NAME@</pattern>
* <enums>
* <org.nuiton.Enum1>
* <org.nuiton.Enum2>
* <...>
* </enums>
* </enumerationSet>
* </enumerationSets>
*
*
* Example with enum {@code enum org.nuiton.Enum1 { A,B }}, will generate i18n keys:
*
* - myPrefix.org.nuiton.Enum1.A
* - myPrefix.org.nuiton.Enum1.B
*
*
* In pattern, you can use variable
*
*
* - {@code @CLASS_NAME@} for enumeration class fully qualified name
* - {@code @CLASS_SIMPLE_NAME@} for enumeration class simple name
* - {@code @NAME@} for enumeration name
* - {@code @ORDINAL@} for enumeration ordinal
*
*
* Moreover, two methods will be also generated according to specified name to translate those keys :
*
* public static String getLabel(Enum)
* public static String getLabel(Locale, Enum)
*
*/
@Parameter(required = true)
private List enumerationSets;
@Override
protected void doAction() throws Exception {
if (packageName == null) {
packageName = getProject().getGroupId() + "." + getProject().getArtifactId().replaceAll("-", ".");
}
File directory = PluginHelper.getFile(outputdirectory, packageName.trim().split("\\."));
File file = new File(directory, className + ".java");
Files.createParentDirs(file);
getLog().info("Will generate to " + file);
BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);
try {
writer.write("// Generated by " + getClass().getName() + " at " + new Date() + "\n");
writer.write("package " + packageName + ";\n");
writer.write("\n");
writer.write("import java.util.Locale;\n");
writer.write("\n");
writer.write("import static org.nuiton.i18n.I18n.l;\n");
writer.write("import static org.nuiton.i18n.I18n.n;\n");
writer.write("import static org.nuiton.i18n.I18n.t;\n");
writer.write("\n");
writer.write("\n");
writer.write("public class " + className + " {\n");
writer.write("\n");
Set names = new HashSet<>();
for (EnumerationSet enumerationSet : enumerationSets) {
if (names.add(enumerationSet.getName())) {
String methodName = "get" + StringUtils.capitalise(enumerationSet.getName());
writer.write(" public static > String " + methodName + "(E e) {\n");
writer.write(" return t(" + methodName + "Key(e));\n");
writer.write(" }\n");
writer.write("\n");
writer.write(" public static > String " + methodName + "(Locale locale, E e) {\n");
writer.write(" return l(locale, " + methodName + "Key(e));\n");
writer.write(" }\n");
writer.write("\n");
writer.write(" protected static > String " + methodName + "Key(E e) {\n");
writer.write(" return " + enumerationSet.transformToMessage() + ";\n");
writer.write(" }\n");
writer.write("\n");
}
}
writer.write(" static {\n\n");
for (EnumerationSet enumerationSet : enumerationSets) {
for (String anEnumType : enumerationSet.getEnums()) {
int ordinal = 0;
String simpleName = anEnumType.substring(anEnumType.lastIndexOf('.') + 1);
for (String name : getEnumConstants(anEnumType)) {
writer.write(" n(\"" + enumerationSet.transformToKey(anEnumType, simpleName, name, (ordinal++) + "") + "\");\n");
}
}
}
writer.write("\n }\n");
writer.write("\n protected static String removeAnonymousSuffix(String className) {\n");
writer.write(" return className.contains(\"$\") ? className.substring(0, className.indexOf(\"$\")) : className;");
writer.write("\n }\n");
writer.write("}\n");
writer.close();
} finally {
IOUtils.closeQuietly(writer);
}
}
private Set getEnumConstants(String anEnumType) throws ClassNotFoundException, IOException {
getLog().info("Scan enum: " + anEnumType);
Set result = new TreeSet<>();
try {
Class aClass = Class.forName(anEnumType);
if (!aClass.isEnum()) {
throw new IllegalStateException("Type " + aClass.getName() + " is not an enum.");
}
for (Object o : aClass.getEnumConstants()) {
result.add(((Enum) o).name());
}
} catch (ClassNotFoundException e) {
// try with antlr4
File basedir = new File(new File(new File(getProject().getBasedir(), "src"), "main"), "java");
File file = PluginHelper.getFile(basedir, anEnumType.trim().split("\\."));
File javaFile = new File(file.getParentFile(), file.getName() + ".java");
if (javaFile.exists()) {
String content = FileUtils.readFileToString(javaFile, "UTF-8");
TokenStream tokenStream = new CommonTokenStream(new Java8Lexer(new ANTLRInputStream(content)));
Java8Parser parser = new Java8Parser(tokenStream);
// see http://stackoverflow.com/a/32918434/2038100
//parser.setErrorHandler(new BailErrorStrategy());
//parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
//parser.getInterpreter().tail_call_preserves_sll = false;
parser.getInterpreter().enable_global_context_dfa = true;
JavaParserVisitor visitor = new JavaParserVisitor(javaFile);
parser.compilationUnit().accept(visitor);
Set names = visitor.getNames();
result.addAll(names);
}
}
return result;
}
protected class JavaParserVisitor extends Java8BaseVisitor {
protected final Set names;
protected final File file;
private JavaParserVisitor(File file) {
this.file = file;
names = new LinkedHashSet<>();
}
public Set getNames() {
return names;
}
@Override
public Void visitEnumConstant(Java8Parser.EnumConstantContext ctx) {
String text = ctx.getChild(0).getText();
names.add(text);
return super.visitEnumConstant(ctx);
}
}
public static class EnumerationSet {
private String name;
private String pattern;
private List enums;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPattern() {
return pattern;
}
public void setPattern(String pattern) {
this.pattern = pattern;
}
public List getEnums() {
return enums;
}
public void setEnums(List enums) {
this.enums = enums;
}
public String transformToKey(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;
}
public String transformToMessage() {
String result = "";
StringTokenizer stringTokenizer = new StringTokenizer(pattern, "@");
while (stringTokenizer.hasMoreTokens()) {
if (!result.isEmpty()) {
result += " + ";
}
String token = stringTokenizer.nextToken();
switch (token) {
case "CLASS_SIMPLE_NAME":
result += "e.getClass().getSimpleName()";
break;
case "CLASS_NAME":
result += "removeAnonymousSuffix(e.getClass().getName())";
break;
case "NAME":
result += "e.name()";
break;
case "ORDINAL":
result += "e.ordinal()";
break;
default:
result += "\"" + token + "\"";
}
}
if (result.endsWith("+")) {
result = result.substring(0, result.length() - 1);
}
return result;
}
}
}