org.nuiton.eugene.GeneratorUtil Maven / Gradle / Ivy
Show all versions of eugene-core Show documentation
/*
* #%L
* EUGene :: EUGene Core
* %%
* Copyright (C) 2004 - 2017 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%
*/
package org.nuiton.eugene;
import com.google.common.base.Joiner;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.eugene.models.Model;
import org.nuiton.eugene.models.extension.tagvalue.TagValueMetadata;
import org.nuiton.eugene.models.extension.tagvalue.TagValueUtil;
import org.nuiton.eugene.models.extension.tagvalue.WithTagValuesOrStereotypes;
import org.nuiton.eugene.models.object.ObjectModel;
import org.nuiton.eugene.models.object.ObjectModelAttribute;
import org.nuiton.eugene.models.object.ObjectModelClass;
import org.nuiton.eugene.models.object.ObjectModelClassifier;
import org.nuiton.eugene.models.object.ObjectModelElement;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelParameter;
import org.nuiton.eugene.models.object.SerialVersionUIDBuilder;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* GeneratorUtil.
*
* Created: 25 aout 2003
*
* @author Benjamin Poussin - [email protected]
*/
public class GeneratorUtil {
public static final String SERIAL_VERSION_UID = "serialVersionUID";
/**
* return parent package of given package (return given package if it is a root package)
* eg : org.nuiton.eugene.models -> org.nuiton.eugene
* eg : org -> org
* warning : org.nuiton.eugene. -> org.nuiton.eugene
*
* @param packageName package
* @return parent package of given package
*/
public static String getParentPackageName(String packageName) {
String parentPackageName = packageName;
int index = packageName.lastIndexOf('.');
if (index != -1) {
parentPackageName = packageName.substring(0, index);
}
return parentPackageName;
}
/**
* @param qualifiedName the fully qualified name to test
* @return class name fr given fully qualified name (return given name if it is not fully qualified)
* eg : org.nuiton.eugene.models.ObjectClass -> ObjectClass
* eg : ObjectClass-> ObjectClass
*/
public static String getClassNameFromQualifiedName(String qualifiedName) {
String className = qualifiedName;
int index = qualifiedName.lastIndexOf('.');
if (index != -1) {
className = qualifiedName.substring(index + 1);
}
return className;
}
/**
* @param qualifiedName the fully qualified name to test
* @return the filename for the given qualified name.
*/
public static String getFilenameFromQualifiedName(String qualifiedName) {
return qualifiedName.replace('.', File.separatorChar);
}
/**
* return all classifiers belonging to the given package recursively. The Collection may be empty.
*
* @param model the model where to look at
* @param packageName the package name to set for classifiers
* @return a Collection containing all classifiers belonging to the given package recursively.
* @see ObjectModelClassifier
*/
public static Collection getClassifiers(
ObjectModel model, String packageName) {
List classifiers = new ArrayList<>();
for (ObjectModelClassifier classifier : model.getClassifiers()) {
if (classifier.getPackageName().startsWith(packageName)) {
classifiers.add(classifier);
}
}
return classifiers;
}
/**
* Indicates if the specified attribute has a primitive type (byte, boolean, ...)
*
* @param attribute the attribute to test
* @return true if the attribute has a primitive type
*/
public static boolean isPrimitiveAttributeType(
ObjectModelAttribute attribute) {
if (isNMultiplicity(attribute)) {
return false;
}
String type = attribute.getType();
return isPrimitiveType(type);
// return "byte".equals(type) || "short".equals(type)
// || "int".equals(type) || "long".equals(type)
// || "float".equals(type) || "double".equals(type)
// || "char".equals(type) || "boolean".equals(type);
}
/**
* Tests if the given type is a primitive type.
*
* @param type the type to test
* @return {@code true} if given type is primitive.
* @since 2.3.2
*/
public static boolean isPrimitiveType(String type) {
return "byte".equals(type) || "short".equals(type)
|| "int".equals(type) || "long".equals(type)
|| "float".equals(type) || "double".equals(type)
|| "char".equals(type) || "boolean".equals(type);
}
/**
* @param type primitive type
* @return the wrap primitive type
* @since 3.0
*/
public static String getPrimitiveWrapType(String type) {
if ("byte".equals(type)) {
return "Byte";
}
if ("short".equals(type)) {
return "Short";
}
if ("int".equals(type)) {
return "Integer";
}
if ("long".equals(type)) {
return "Long";
}
if ("float".equals(type)) {
return "Float";
}
if ("double".equals(type)) {
return "Double";
}
if ("char".equals(type)) {
return "Character";
}
if ("boolean".equals(type)) {
return "Boolean";
}
return null;
}
/**
* return an init value for the specified attribute
*
* @param attribute the attribute to test
* @return a String with the corresponding attribute init value
*/
public static String getInitValue(ObjectModelAttribute attribute) {
if (isNMultiplicity(attribute)) {
return "new java.util.ArrayList()";
}
return getInitValue(attribute.getType());
}
public static String getInitValue(String type) {
if ("byte".equals(type)) {
return "0";
}
if ("short".equals(type)) {
return "0";
}
if ("int".equals(type)) {
return "0";
}
if ("long".equals(type)) {
return "0";
}
if ("float".equals(type)) {
return "0";
}
if ("double".equals(type)) {
return "0";
}
if ("char".equals(type)) {
return "\u0000";
}
if ("boolean".equals(type)) {
return "false";
}
if ("java.lang.String".equals(type)) {
return null;
}
if ("java.lang.Date".equals(type)) {
return null;
}
return null;
}
public static String getCastValue(String type, String o) {
if ("byte".equals(type)) {
return "((Byte)" + o + ").byteValue()";
}
if ("short".equals(type)) {
return "((Short)" + o + ").shortValue()";
}
if ("int".equals(type)) {
return "((Integer)" + o + ").intValue()";
}
if ("long".equals(type)) {
return "((Long)" + o + ").longValue()";
}
if ("float".equals(type)) {
return "((Float)" + o + ").floatValue()";
}
if ("double".equals(type)) {
return "((Double)" + o + ").doubleValue()";
}
if ("char".equals(type)) {
return "((Character)" + o + ").charValue()";
}
if ("boolean".equals(type)) {
return "((Boolean)" + o + ").booleanValue()";
}
if ("void".equals(type)) {
return "";
}
return "(" + type + ")" + o;
}
public static String getHashCodeExpression(String type, String o) {
String result = o;
if ("byte".equals(type)) {
result = "new Byte(" + o + ")";
}
if ("short".equals(type)) {
result = "new Short(" + o + ")";
}
if ("int".equals(type)) {
result = "new Integer(" + o + ")";
}
if ("long".equals(type)) {
result = "new Long(" + o + ")";
}
if ("float".equals(type)) {
result = "new Float(" + o + ")";
}
if ("double".equals(type)) {
result = "new Double(" + o + ")";
}
if ("char".equals(type)) {
result = "new Character(" + o + ")";
}
if ("boolean".equals(type)) {
result = "new Boolean(" + o + ")";
}
return result + ".hashCode()";
}
/**
* @param attribute the attribute to test
* @return vrai si la cardinalite de l'attribut est superieur a 1, c-a-d
* si MaxMultiplicity == -1 ou > 1
*/
public static boolean isNMultiplicity(ObjectModelAttribute attribute) {
return isNMultiplicity(attribute.getMaxMultiplicity());
}
public static boolean isNMultiplicity(int multiplicity) {
return multiplicity == -1 || multiplicity > 1;
}
/**
* @param attribute the attribute to test
* @return true is the multiplicity of the given attribute is exactly 1
*/
public static boolean isOneMultiplicity(ObjectModelAttribute attribute) {
return attribute != null && attribute.getMinMultiplicity() == 1 &&
attribute.getMaxMultiplicity() == 1;
}
/**
* @param word the word to decapitalize
* @return the decapitalized word
*/
public static String toLowerCaseFirstLetter(String word) {
return word.substring(0, 1).toLowerCase() + word.substring(1);
}
/**
* @param attribute the attribute to test
* @return true if the given attribute is a composition (composant of the reverse attribute)
*/
public static boolean isComposition(ObjectModelAttribute attribute) {
boolean composition = false;
if (attribute != null && attribute.getReverseAttribute() != null) {
composition = attribute.getReverseAttribute().isComposite();
}
return composition;
}
/**
* Tests if an attribute is a boolean primitive.
*
* @param attribute the attribute to test
* @return {@code true} if attribute is a primitive boolean
* @since 2.4.1
*/
public static boolean isBooleanPrimitive(ObjectModelAttribute attribute) {
String type = attribute.getType();
return isBooleanPrimitive(type);
}
/**
* Tests if an type is a boolean primitive.
*
* @param type the type to test
* @return {@code true} if type is a primitive boolean
* @since 2.11
*/
public static boolean isBooleanPrimitive(String type) {
return "boolean".equals(type);
}
public static String getParsingExpression(String type,
String attributeStringName) {
if ("byte".equals(type)) {
return "Byte.parseByte(" + attributeStringName + ")";
}
if ("short".equals(type)) {
return "Short.parseShort(" + attributeStringName + ")";
}
if ("int".equals(type)) {
return "Integer.parseInt(" + attributeStringName + ")";
}
if ("long".equals(type)) {
return "Long.parseLong(" + attributeStringName + ")";
}
if ("float".equals(type)) {
return "Float.parseFloat(" + attributeStringName + ")";
}
if ("double".equals(type)) {
return "Double.parseDouble(" + attributeStringName + ")";
}
if ("char".equals(type)) {
return attributeStringName + ".charAt(0)";
}
if ("boolean".equals(type)) {
return "Boolean.parseBoolean(" + attributeStringName + ")";
}
if ("java.lang.String".equals(type)) {
return attributeStringName;
}
if ("java.util.Date".equals(type)) {
return "dateParser.parse(" + attributeStringName + ")";
}
return null;
}
public static String getFormatingExpression(String type,
String attributeStringName) {
if ("byte".equals(type)) {
return "Byte.toString(" + attributeStringName + ")";
}
if ("short".equals(type)) {
return "Short.toString(" + attributeStringName + ")";
}
if ("int".equals(type)) {
return "Integer.toString(" + attributeStringName + ")";
}
if ("long".equals(type)) {
return "Long.toString(" + attributeStringName + ")";
}
if ("float".equals(type)) {
return "Float.toString(" + attributeStringName + ")";
}
if ("double".equals(type)) {
return "Double.toString(" + attributeStringName + ")";
}
if ("char".equals(type)) {
return "Character.toString(" + attributeStringName + ")";
}
if ("boolean".equals(type)) {
return "Boolean.parseBoolean(" + attributeStringName + ")";
}
if ("java.lang.String".equals(type)) {
return attributeStringName;
}
if ("java.util.Date".equals(type)) {
return "dateParser.format(" + attributeStringName + ")";
}
return null;
}
/**
* Used to return the {@code operation} parameter names as a string
* separated by a comma. Usefull for operation call in templates writing.
*
* @param operation to treate
* @return the string corresponding to the list of operation parameter
* names separated by a ', '.
*/
public static String getOperationParametersListName(ObjectModelOperation operation) {
return Joiner.on(", ").join(operation.getParameters().stream().map(ObjectModelParameter::getName).collect(Collectors.toList()));
}
/**
* Renvoie si l'attribut passé en paramètre est premier lexicographiquement
* par rapport à son attribut inverse (si celui ci existe).
*
* @param attr L'attribut dont on veut savoir s'il est le premier
* @return true, si l'attribut est premier (lexico ou pas de reverse attribute), false dans les autres cas
*/
public static boolean isFirstAttribute(ObjectModelAttribute attr) {
boolean firstAttribute = true;
if (attr.getReverseAttribute() != null) {
firstAttribute = attr.getName().compareTo(
attr.getReverseAttribute().getName()) < 0;
}
return firstAttribute;
}
/**
* Indique si l'élément spécifié dispose de documentation
*
* @param element l'élément à tester
* @return true s'il y a documentation, false sinon
*/
public static boolean hasDocumentation(ObjectModelElement element) {
return StringUtils.isNotEmpty(element.getDocumentation());
}
/**
* Indique si la chaine de caratère n'est pas vide (null ou "")
*
* @param s la chaine de caractères à tester
* @return true si s
n'est pas vide
* @deprecated since 2.3, use the method {@link StringUtils#isNotEmpty(CharSequence)}
*/
@Deprecated
public static boolean notEmpty(String s) {
return s != null && !"".equals(s);
}
/**
* Cherches et renvoie la valeur du tagvalue indique sur cet element,
* sinon sur le model.
*
* @param tagName le nom du tag
* @param element l'élément à tester
* @param model le modele utilisé
* @return la valeur du tagValue ou null
* @deprecated since 2.9 (will be remove in version 3.0), prefer use now {@link TagValueUtil#findTagValue(TagValueMetadata, WithTagValuesOrStereotypes...)}
*/
@Deprecated
public static String findTagValue(String tagName,
ObjectModelElement element,
Model model) {
if (element == null) {
if (model != null) {
String value = model.getTagValue(tagName);
if (!StringUtils.isEmpty(value)) {
return value;
}
}
return null;
}
String value = element.getTagValue(tagName);
if (!StringUtils.isEmpty(value)) {
return value;
}
//On va chercher sur l'element declarant
return findTagValue(tagName, element.getDeclaringElement(), model);
}
public static boolean hasStereotype(ObjectModelElement element,
String stereotype) {
return element.hasStereotype(stereotype) ||
element.hasStereotype(stereotype.toLowerCase());
}
/**
* For the given class and its attributes, this method computes a
* serialVersionUID. Exemple, returns "123456789L".
* This id will change only if the type or the order of an attribute
* changes.
*
* @param clazz the class to use
* @return the generated serialVersionUID
* @deprecated since 2.4, prefer use the method {@link #generateSerialVersionUID(ObjectModelClassifier)}
*/
@Deprecated
public static String computeSerialVersionUID(ObjectModelClass clazz) {
String query = clazz.getQualifiedName() + "#";
for (ObjectModelAttribute attr : clazz.getAttributes()) {
query += "-" + attr.getType();
}
String result = query.hashCode() + "L";
return result;
}
/**
* Suppress packageName from a fullQualifiedName, even if it contains
* List, Map or other generics.
*
* See JUnit test for matching expressions.
*
* @param str FullQualifiedName for an attribute type (for exemple)
* @return the simple name associated to the str given
*/
public static String getSimpleName(String str) {
String result = getSimpleName(str, false);
return result;
}
/**
* Suppress packageName from a fullQualifiedName, even if it contains List,
* Map or other generics.
*
* See JUnit test for matching expressions.
*
* @param str fullQualifiedName for an attribute type (for exemple)
* @param removeGenericDefinition a flag to remove any generic definition at the beginning of the expression
* @return the simple name associated to the str given
* @since 2.3
*/
public static String getSimpleName(String str, boolean removeGenericDefinition) {
if (removeGenericDefinition) {
str = removeGenericDefinition(str);
}
// variable array type
boolean variableArrayType = false;
if (str.endsWith("...")) {
variableArrayType = true;
str = str.substring(0, str.length() - 3);
}
if (str.startsWith("\"") && str.endsWith("\"")) {
return str;
}
//return str.replaceAll("[a-zA-Z]\\w*\\.","");
String result = str.replaceAll("\\p{Alpha}\\w*\\.", "");
if (variableArrayType) {
result += "...";
}
return result;
}
/**
* Remove any generics definition at the beginning of a string.
*
* For example :
*
* <T> T -> T
*
*
* @param str the string to parse
* @return the string without any
* @since 2.3
*/
public static String removeGenericDefinition(String str) {
// always trim the string
String result = str.trim();
if (!result.startsWith("<")) {
// not starting by a generics definition, no treatment to do
return str;
}
int i = 0;
for (int length = result.length(), count = 0; i < length; i++) {
char c = result.charAt(i);
if ('<' == c) {
count++;
} else if ('>' == c) {
count--;
}
if (count == 0) {
break;
}
}
// the i position was on the last closing caracter, can safely
// remove until this position + 1
result = result.substring(i + 1);
// remove any starting spaces
while (result.startsWith(" ")) {
result = result.substring(1);
}
return result;
}
/**
* Remove any generics definition at the beginning of a string.
*
* For example :
*
* <T> T -> T
*
*
* @param str the string to parse
* @return the string without any
* @since 2.6.3
*/
public static String removeAnyGenericDefinition(String str) {
// always trim the string
String result = str.trim();
if (!result.contains("<")) {
// no generics definition, no treatment to do
return str;
}
result = result.substring(0, result.indexOf('<'));
return result;
}
/**
* @param str the string to parse
* @return the string without any
* @since 2.3.2
*/
public static String[] splitGenericDefinition(String str) {
// always trim the string
String result = str.trim();
if (!result.startsWith("<")) {
// not starting by a generics definition, no treatment to do
return new String[]{str};
}
int i = 0;
for (int length = result.length(), count = 0; i < length; i++) {
char c = result.charAt(i);
if ('<' == c) {
count++;
} else if ('>' == c) {
count--;
}
if (count == 0) {
break;
}
}
// the i position was on the last closing caracter, can safely
// remove until this position + 1
String prefix = result.substring(0, i + 1);
String end = result.substring(i + 1);
// remove any starting spaces
while (end.startsWith(" ")) {
end = end.substring(1);
}
return new String[]{prefix, end};
}
/**
* Parse a fully qualified generic java type, and extract each imbricated types.
*
* @param str string to parse
* @return set of found types
*/
public static Set getTypesList(String str) {
Set results = new HashSet<>();
// remove extends, super
String localStr = str.replaceAll("([\\w\\?]+ extends|[\\w\\?]+ super|new)", "");
// replace non java enabled characters
localStr = localStr.replaceAll("[^\\w\\.]", " ");
// each space separated part is an import
String[] strArray = localStr.split("\\s+");
for (String strImport : strArray) {
String localStrImport = strImport.trim();
if (!localStrImport.isEmpty()) {
results.add(localStrImport);
}
}
return results;
}
/**
* Convertit un nom de variable en nom de constante.
*
* @param variableName le nom de variable a convertir
* @return le nom de la constante à partir du nom de la variable
*/
public static String convertVariableNameToConstantName(String variableName) {
//TODO Faire des tests pour savoir si variableName est non null et valide
//TODO Ameliorer l'algo pour tenir compte des caractères non alpha
//TODO pour le moment cela convient, donc...
StringBuilder buffer = new StringBuilder();
boolean lastCarIsUp = false;
for (int i = 0, j = variableName.length(); i < j; i++) {
char c = variableName.charAt(i);
boolean carIsUp = Character.isUpperCase(c);
if (i > 0 && !lastCarIsUp && carIsUp) {
// ajout d'un _
buffer.append('_');
}
if (carIsUp) {
buffer.append(c);
} else {
buffer.append(Character.toUpperCase(c));
}
lastCarIsUp = carIsUp;
}
return buffer.toString();
}
/**
* Convertit un nom de constante en nom de variable.
*
* @param constantName le nom de constante a convertir
* @return le nom de la variable à partir du nom de la constante
* @since 3.0
*/
public static String convertConstantNameToVariableName(String constantName) {
StringBuilder buffer = new StringBuilder();
boolean lastCarIsUp = false;
for (int i = 0, j = constantName.length(); i < j; i++) {
char c = constantName.charAt(i);
if ('_' == c) {
lastCarIsUp = true;
continue;
}
if (lastCarIsUp) {
c = Character.toUpperCase(c);
lastCarIsUp = false;
} else {
c = Character.toLowerCase(c);
}
buffer.append(c);
}
return buffer.toString();
}
/**
* Renvoie le nom de l'attribut de classe d'association en fonction des cas:
* Si l'attribut porte le même nom que le type (extrémité inverse de
* l'association), on lui ajoute le nom de la classe d'association
*
* @param attr l'attribut a traiter
* @return le nom de l'attribut de classe d'association
* @since 2.0.2
*/
public static String getAssocAttrName(ObjectModelAttribute attr) {
String typeName = attr.getType().substring(
attr.getType().lastIndexOf(".") + 1);
String result = attr.getName();
if (attr.getName().equalsIgnoreCase(typeName)) {
result += StringUtils.capitalize(
attr.getAssociationClass().getName());
}
return result;
}
/**
* Generates the serialVersionUID of the given {@code classifier}.
*
* @param classifier the classifier
* @return the value of the serialVersionUID
*/
public static long generateSerialVersionUID(ObjectModelClassifier classifier) {
long result = SerialVersionUIDBuilder.computeDefaultSUID(classifier);
return result;
}
/**
* Recupère le fichier mirroir du fichier {@code file} donnée qui est dans
* l'arborescence de {@code inputDirectory} dans le répertoire
* {@code ouputDirectory}.
*
* @param inputDirectory le répertoire de départ
* @param outputDirectory le répertoire cible
* @param file le fichier
* @return le fichier mirroir dans le répertoire cible
* @since 1.4.2
*/
public static File getRelativeFile(File inputDirectory,
File outputDirectory,
File file) {
String inputPath = inputDirectory.getAbsolutePath();
String s = file.getAbsolutePath();
int index = s.indexOf(inputPath);
if (index == -1) {
throw new IllegalArgumentException(
"File " + file + " is not in " + inputDirectory);
}
String relativePath = s.substring(inputPath.length());
File result = new File(outputDirectory, relativePath);
return result;
}
/**
* Recupère le fichier dans le même répertoire que le fichier donné et dont
* on a changé l'extension.
*
* @param file le fichier d'origine
* @param newExtension la nouvelle extension à utiliser
* @return le fichier dont on a changé l'extension
* @throws IOException si aucune extension trouvé dans le fichier d'origine
* @since 1.4.2
*/
public static File changeExtension(File file,
String newExtension) throws IOException {
String name = file.getName();
String newName = changeExtension(name, newExtension);
return new File(file.getParentFile(), newName);
}
/**
* Change l'extension du fichier en entrée avec la nouvelle extension
*
* @param name le nom de fichier à transformer
* @param newExtension la nouvelle extension à utiliser
* @return le nouveau nom de fichier
* @throws IOException si aucune extension trouvé dans le fichier d'origine
* @since 1.4.2
*/
public static String changeExtension(String name,
String newExtension) throws IOException {
String extension = FilenameUtils.getExtension(name);
if (extension == null) {
throw new IOException(String.format("Could not find extension for name %s.", name));
}
String nameWithoutExtension = name.substring(0, name.length() - extension.length());
return nameWithoutExtension + newExtension;
}
} // GeneratorUtil