org.nuiton.eugene.java.JavaGeneratorUtil Maven / Gradle / Ivy
/*
* #%L
* EUGene :: EUGene
*
* $Id: JavaGeneratorUtil.java 1380 2014-06-19 06:47:21Z tchemit $
* $HeadURL: https://svn.nuiton.org/eugene/tags/eugene-2.11/eugene/src/main/java/org/nuiton/eugene/java/JavaGeneratorUtil.java $
* %%
* Copyright (C) 2004 - 2010 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%
*/
package org.nuiton.eugene.java;
import org.apache.commons.lang3.StringUtils;
import org.nuiton.eugene.EugeneStereoTypes;
import org.nuiton.eugene.EugeneTagValues;
import org.nuiton.eugene.GeneratorUtil;
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.ObjectModelJavaModifier;
import org.nuiton.eugene.models.object.ObjectModelModifier;
import org.nuiton.eugene.models.object.ObjectModelOperation;
import org.nuiton.eugene.models.object.ObjectModelParameter;
import org.nuiton.util.StringUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* Utility class for pure java templates.
*
* @author tchemit
* @since 2.0.2
*/
public class JavaGeneratorUtil extends GeneratorUtil {
public static final String OPERATION_GETTER_DEFAULT_PREFIX = "get";
public static final String OPERATION_GETTER_BOOLEAN_PREFIX = "is";
/**
* dependency to add constants in interfaces via an enumeration.
*
* The literals of enumeration will be the value, and constant names will
* be generated by transformers.
*
* @since 2.0.2
*/
public static final String DEPENDENCIES_CONSTANTS = "constants";
/**
* Duplicates in the {@code target} classifier the given {@code operations}
* using a {@code transformer} to modify model.
*
* @param transformer the transformer to use
* @param operations operations to duplicate
* @param target where to duplicate operations
* @param useVisibility flag to use operation visibilty to compute his
* modifiers
* @param extraModifiers scopes to apply to all operations
*/
public static void cloneOperations(ObjectModelTransformerToJava transformer,
Iterable operations,
ObjectModelClassifier target,
boolean useVisibility,
ObjectModelModifier... extraModifiers) {
for (ObjectModelOperation op : operations) {
ObjectModelOperation resultOp;
ObjectModelModifier[] modifiers;
if (useVisibility) {
// compute visibility modifer
String visibility = op.getVisibility();
ObjectModelModifier modifier =
ObjectModelJavaModifier.fromVisibility(visibility);
int length = extraModifiers.length;
if (length == 0) {
modifiers = new ObjectModelModifier[]{modifier};
} else {
modifiers = new ObjectModelModifier[length + 1];
modifiers[0] = modifier;
System.arraycopy(extraModifiers, 0, modifiers, 1, length);
}
} else {
// just use the incoming modifiers
modifiers = extraModifiers;
}
resultOp = transformer.addOperation(target,
op.getName(),
op.getReturnType(),
modifiers
);
for (ObjectModelParameter param : op.getParameters()) {
transformer.addParameter(resultOp,
param.getType(),
param.getName()
);
}
for (String exception : op.getExceptions()) {
transformer.addException(resultOp, exception);
}
}
}
/**
* Check if the given classifier has the
* {@link EugeneStereoTypes#STEREOTYPE_SKIP} stereotype.
*
* @param classifier classifier to test
* @return {@code true} if stereotype was found, {@code false otherwise}
* @see EugeneStereoTypes#STEREOTYPE_SKIP
* @since 2.5
* @deprecated since 2.9, use now {@link EugeneStereoTypes#hasSkipStereotype(ObjectModelClassifier)}
*/
@Deprecated
public static boolean hasSkipStereotype(ObjectModelClassifier classifier) {
return EugeneStereoTypes.hasSkipStereotype(classifier);
}
/**
* Cherche et renvoie le prefixe i18n à utiliser sur cet element, sinon sur
* le model.
*
* @param element l'élément à tester
* @param model le modele utilisé
* @return le prefix i18n ou null si non spécifié
* @since 2.3
* @deprecated since 2.9, use now {@link EugeneTagValues#getI18nPrefixTagValue(ObjectModelElement, ObjectModel)}
*/
@Deprecated
public static String getI18nPrefixTagValue(ObjectModelElement element,
ObjectModel model) {
return EUGENE_TAG_VALUES.getI18nPrefixTagValue(element, model);
}
/**
* Obtain the value of the {@link EugeneTagValues#TAG_DO_NOT_GENERATE_BOOLEAN_GET_METHODS}
* tag value on the given model or classifier.
*
* It will first look on the model, and then in the given classifier.
*
* @param model model to seek
* @param classifier classifier to seek
* @return the none empty value of the found tag value or {@code null} if not found nor empty.
* @see EugeneTagValues#TAG_DO_NOT_GENERATE_BOOLEAN_GET_METHODS
* @since 2.4.1
* @deprecated since 2.9, use now {@link EugeneTagValues#isDoNotGenerateBooleanGetMethods(ObjectModelClassifier, ObjectModel)}
*/
@Deprecated
public static boolean isDoNotGenerateBooleanGetMethods(ObjectModel model,
ObjectModelClassifier classifier) {
boolean value = EUGENE_TAG_VALUES.isDoNotGenerateBooleanGetMethods(classifier, model);
return value;
}
/**
* Obtain the value of the {@link EugeneTagValues#TAG_CONSTANT_PREFIX}
* tag value on the given model or classifier.
*
* It will first look on the model, and then in the given classifier.
*
* @param model model to seek
* @param classifier classifier to seek
* @return the none empty value of the found tag value or {@code null} if not found nor empty.
* @see EugeneTagValues#TAG_CONSTANT_PREFIX
* @since 2.3
* @deprecated since 2.9, use now {@link EugeneTagValues#getConstantPrefixTagValue(ObjectModelClassifier, ObjectModel)}
*/
@Deprecated
public static String getConstantPrefixTagValue(ObjectModel model,
ObjectModelClassifier classifier) {
String value = EUGENE_TAG_VALUES.getConstantPrefixTagValue(classifier, model);
return value;
}
/**
* Convertit une propriété javaBean son suffix utilisé pour écrire les
* getter/setter correspondant.
*
* @param propertyName le nom de propriété a convertir
* @return le nom capitalizé de la propriété JavaBean
* @since 2.4.2
*/
public static String capitalizeJavaBeanPropertyName(String propertyName) {
if (StringUtils.isEmpty(propertyName)) {
return propertyName;
}
if (propertyName.length() == 1) {
// simple case :
return propertyName.toUpperCase();
}
// check if second caracter is up
char c = propertyName.charAt(1);
boolean carIsUp = Character.isUpperCase(c);
if (carIsUp) {
// this is a special and strange case : must not capitalize first char
return propertyName;
}
return StringUtils.capitalize(propertyName);
}
/**
* Split the given fqn which contains a generic declaration into his parts.
*
* Example :
*
* java.util.List<Integer> : [java.util.List, Integer]
* java.util.List<java.util.List<Integer>> : [java.util.List, java.util.List<Integer>]
* java.util.Map<Integer, Integer> : [java.util.Map, Integer, Integer]
* java.util.Map<Integer, java.util.List<Integer>> : [java.util.Map, Integer, java.util.List<Integer>]
*
*
* Note: We only deal with one level of generics here in
* order to be able easly to rebuild after all the fqn with simple names...
*
* @param fqn the fqn to split
* @return the array of all parts of the fqn.
* @since 2.3.2
*/
public static String[] splitGeneric(String fqn) {
if (fqn == null) {
return null;
}
int firstPartIndex = fqn.indexOf('<');
if (firstPartIndex == -1) {
// no generics, just return the fqn
return new String[]{fqn};
}
List parts = new ArrayList();
parts.add(fqn.substring(0, firstPartIndex));
String rest = fqn.substring(firstPartIndex + 1,
fqn.lastIndexOf('>'));
if (containsGenerics(rest) && rest.contains(",")) {
// there is others generics in generics, worse case...
int begin = 0;
int count = 0;
int max = rest.length();
for (int i = 0; i < max; i++) {
char c = rest.charAt(i);
if (c == '<') {
count++;
} else if (c == '>') {
count--;
} else if (c == ',') {
// arrives on a possible split
if (count == 0) {
// can safely add this part
String part = rest.substring(begin, i);
parts.add(part.trim());
begin = i + 1;
}
}
}
// there is a last part to add ?
if (begin < max) {
String part = rest.substring(begin, max);
parts.add(part.trim());
}
} else {
// simple case : each part of the generics has no other generics
String[] split = rest.split(",");
for (String part : split) {
parts.add(part.trim());
}
}
return parts.toArray(new String[parts.size()]);
}
/**
* Join generics parts of a fqn into aparts.
*
* Example :
*
* [java.util.List, Integer] : java.util.List<Integer>
* [java.util.List, java.util.List<Integer>] : java.util.List<java.util.List<Integer>>
* [java.util.Map, Integer, Integer] : java.util.Map<Integer, Integer>
* [java.util.Map, Integer, java.util.List<Integer>] : java.util.Map<Integer, java.util.List<Integer>>
*
*
* @param genericParts the parts of fqn
* @return the fqn from his parts
* @since 2.3.2
*/
public static String joinGeneric(String... genericParts) {
if (genericParts == null || genericParts.length == 0) {
// this case should never happen ?
return null;
}
if (genericParts.length == 1) {
// in fact, no generics
return genericParts[0];
}
StringBuilder sb = new StringBuilder(genericParts[0]);
sb.append("<").append(genericParts[1]);
for (int i = 2, max = genericParts.length; i < max; i++) {
String genericPart = genericParts[i];
sb.append(", ").append(genericPart);
}
sb.append('>');
return sb.toString();
}
/**
* Tells if the given fqn contains a generic declaration (says contains a
* {@code <} caracter).
*
* @param fqn the fqn to test
* @return {@code true} if given fqn contains a generic declaration
* @since 2.3.2
*/
public static boolean containsGenerics(String fqn) {
return fqn.contains("<");
}
/**
* Split the given fqns gieven the list separator.
*
* Example :
*
* Boolean, File : [Boolean, File]
* Boolean , java.util.List<Integer> : [Boolean, java.util.List<Integer>]
*
*
*
* Note: You can NOT use as separator {@code '<'} nor
* {@code '>'} nor {@code ' '}.
*
* @param fqns the fqn list to split
* @param separator the fqn separactor char
* @return the array of all parts of the fqn.
* @since 2.3.2
*/
public static String[] splitFqnList(String fqns, char separator) {
if (separator == '<' || separator == '>' || separator == ' ') {
throw new IllegalArgumentException(
"Can not use '<' nor '>' for the separator");
}
if (fqns == null) {
return null;
}
List parts = new ArrayList();
// there is others generics in generics, worse case...
int begin = 0;
int count = 0;
int max = fqns.length();
for (int i = 0; i < max; i++) {
char c = fqns.charAt(i);
if (c == '<') {
count++;
} else if (c == '>') {
count--;
} else if (c == separator) {
// arrives on a possible split
if (count == 0) {
// can safely add this part
String part = fqns.substring(begin, i);
parts.add(part.trim());
begin = i + 1;
}
}
}
// there is a last part to add ?
if (begin < max) {
String part = fqns.substring(begin, max);
parts.add(part.trim());
}
return parts.toArray(new String[parts.size()]);
}
public static boolean isOrdered(ObjectModelAttribute attr) {
return attr.isOrdered() || EugeneStereoTypes.hasOrderedStereotype(attr) || EugeneStereoTypes.hasIndexedStereotype(attr);
}
public static Class> getCollectionType(ObjectModelAttribute attr) {
boolean ordered = isOrdered(attr);
boolean unique = EugeneStereoTypes.hasUniqueStereotype(attr);
// Change type for Multiple attribute
Class> result;
if (ordered) {
if (unique) {
result = LinkedHashSet.class;
} else {
result = List.class;
}
} else {
if (unique) {
result = Set.class;
} else {
result = Collection.class;
}
}
return result;
}
public static Class> getCollectionInstanceType(ObjectModelAttribute attr) {
boolean ordered = isOrdered(attr);
boolean unique = EugeneStereoTypes.hasUniqueStereotype(attr);
// Change type for Multiple attribute
Class> result;
if (ordered) {
if (unique) {
result = LinkedHashSet.class;
} else {
result = LinkedList.class;
}
} else {
if (unique) {
result = HashSet.class;
} else {
result = LinkedList.class;
}
}
return result;
}
/**
* Used to return the {@code operation} parameters for its declaration :
* type and name of each parameter will be join as a string separated by a
* comma. Usefull for operation parameters declaration in templates writing.
*
* @param operation to treate
* @return the string corresponding to the list of operation parameters
* for declaration syntax.
*/
public static String getOperationParametersListDeclaration(
ObjectModelOperation operation) {
String result = StringUtil.join(
operation.getParameters(),
OBJECT_MODEL_PARAMETER_TO_STRING_TYPE,
", ",
false);
return result;
}
/**
* ToString contract for ObjectModelParameter with type and name. This
* contract is used in
* {@link StringUtil#join(Iterable, org.nuiton.util.StringUtil.ToString, String, boolean)}
*/
static final StringUtil.ToString
OBJECT_MODEL_PARAMETER_TO_STRING_TYPE =
new StringUtil.ToString() {
@Override
public String toString(ObjectModelParameter param) {
return new StringBuilder(getAttributeInterfaceType(param)).
append(' ').
append(param.getName()).
toString();
}
};
/**
* @param clazz the class where to look at
* @return sous forme de String la liste des déclarations des attributes d'une classe donnée
*/
public static String getClassAttributesListDeclaration(
ObjectModelClass clazz) {
StringBuilder result = new StringBuilder();
Collection params = clazz.getAttributes();
for (Iterator j = params.iterator(); j.hasNext(); ) {
ObjectModelAttribute attr = j.next();
result.append(getAttributeInterfaceType(attr, true)).append(" ").append(attr.getName());
if (j.hasNext()) {
result.append(", ");
}
}
return result.toString();
}
/**
* @param attribute the attribute to test
* @return the type of the given attribute
* @see #getAttributeInterfaceType(ObjectModelParameter, boolean)
*/
public static String getAttributeInterfaceType(ObjectModelParameter attribute) {
return getAttributeInterfaceType(attribute, false);
}
/**
* Retourne le type de l'attribut, c-a-d une List ou une collection
* ou le type defini si la cardinalité n'est pas multiple
*
* @param attribute the attribute to test
* @param useGenerics {@code true} if the attribute use a generic type
* @return attribute type
*/
public static String getAttributeInterfaceType(ObjectModelParameter attribute,
boolean useGenerics) {
return getAttributeInterfaceType(attribute, attribute.getType(), useGenerics);
}
/**
* Retourne le type de l'attribut, c-a-d une List ou une collection
* ou le type defini si la cardinalité n'est pas multiple
*
* @param attribute the attribute to test
* @param attributeType the attribute type
* @param useGenerics {@code true} if the attribute use a generic type
* @return attribute type
*/
public static String getAttributeInterfaceType(ObjectModelParameter attribute,
String attributeType,
boolean useGenerics) {
String result;
if (attribute instanceof ObjectModelAttribute
&& isNMultiplicity((ObjectModelAttribute) attribute)) {
result = getCollectionType((ObjectModelAttribute) attribute).getName();
if (useGenerics) {
result += "<" + attributeType + ">";
}
} else {
result = attributeType;
}
return result;
}
public static String getAttributeImplementationType(ObjectModelParameter attribute,
String attributeType,
boolean useGenerics) {
String result;
if (attribute instanceof ObjectModelAttribute
&& isNMultiplicity((ObjectModelAttribute) attribute)) {
result = getCollectionInstanceType((ObjectModelAttribute) attribute).getName();
if (useGenerics) {
result += "<" + attributeType + ">";
}
} else {
result = attributeType;
}
return result;
}
public static String getAttributeImplementationType(ObjectModelParameter attribute,
boolean useGenerics) {
return getAttributeImplementationType(attribute, attribute.getType(), useGenerics);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy