org.kie.workbench.common.services.datamodeller.codegen.GenerationTools.java Source code

Java tutorial

Introduction

Here is the source code for org.kie.workbench.common.services.datamodeller.codegen.GenerationTools.java

Source

/**
 * Copyright 2012 Red Hat, Inc. and/or its affiliates.
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.kie.workbench.common.services.datamodeller.codegen;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.kie.workbench.common.services.datamodeller.core.Annotation;
import org.kie.workbench.common.services.datamodeller.core.AnnotationDefinition;
import org.kie.workbench.common.services.datamodeller.core.AnnotationValuePairDefinition;
import org.kie.workbench.common.services.datamodeller.core.DataObject;
import org.kie.workbench.common.services.datamodeller.core.HasAnnotations;
import org.kie.workbench.common.services.datamodeller.core.JavaClass;
import org.kie.workbench.common.services.datamodeller.core.Method;
import org.kie.workbench.common.services.datamodeller.core.ObjectProperty;
import org.kie.workbench.common.services.datamodeller.core.Parameter;
import org.kie.workbench.common.services.datamodeller.core.Type;
import org.kie.workbench.common.services.datamodeller.core.Visibility;
import org.kie.workbench.common.services.datamodeller.util.DataModelUtils;
import org.kie.workbench.common.services.datamodeller.util.FileHashingUtils;
import org.kie.workbench.common.services.datamodeller.util.NamingUtils;
import org.kie.workbench.common.services.datamodeller.util.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Helper tools to generate names and other stuff easily from code adf engine.
 */
public class GenerationTools {

    public static final String EOL = System.getProperty("line.separator");

    private static final Logger logger = LoggerFactory.getLogger(GenerationTools.class);
    private static final String TAB = "    ";

    private static final String START_INDENT = "\n\n";
    private static final String ANNOTATION_START_INDENT = "\n";
    private static final String LINE_INDENT = "    ";
    private static final String END_INDENT = "\n";

    /**
     * Constant inherited for drools world that prevents from generating the all fields constructor if a class has
     * >= 120 fields.
     */
    public static final int MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR = 120;

    public String fitToSize(int size, String name, char padChar) {
        int n = size - name.length();

        StringBuffer buf = new StringBuffer();

        buf.append(name);

        for (int i = 0; i < n; i++) {
            buf.append(padChar);
        }

        return buf.toString();
    }

    public String toJavaGetter(String name, String className) {
        String prefix = NamingUtils.BOOLEAN.equals(className != null ? className.trim() : null) ? "is" : "get";
        return toJavaAccessor(prefix, name);
    }

    public String toJavaSetter(String name) {
        return toJavaAccessor("set", name);
    }

    private String toJavaAccessor(String prefix, String name) {
        if (name == null || name.length() == 0) {
            return name;
        }

        StringBuilder method = new StringBuilder(prefix);

        if (name.charAt(0) == '_') {
            return method.append(name).toString();
        }

        if (name.length() == 1) {
            return method.append(name.toUpperCase()).toString();
        }

        if (Character.isUpperCase(name.charAt(0))) {
            return method.append(name).toString();
        }

        if (Character.isUpperCase(name.charAt(1))) {
            return method.append(name).toString();
        } else {
            return method.append(StringUtils.capitalize(name)).toString();
        }
    }

    private String toJavaName(String name, boolean firstLetterIsUpperCase) {

        name = name.toLowerCase();

        StringBuffer res = new StringBuffer();

        boolean nextIsUpperCase = firstLetterIsUpperCase;

        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);

            if (nextIsUpperCase) {
                c = Character.toUpperCase(c);
            }

            if (Character.isLetter(c)) {
                res.append(c);
                nextIsUpperCase = false;
            } else {
                nextIsUpperCase = true;
            }
        }

        return res.toString();
    }

    public String toJavaVar(String name) {
        return name;
    }

    public String getFilePath(String packageName, String simpleClassName, String extension) {
        if (packageName != null) {
            packageName = "/" + packageName.replace(".", "/");
        } else {
            packageName = "";
        }

        return packageName + "/" + toFileName(simpleClassName) + "." + extension;
    }

    public String toFileName(String name) {
        return name.replaceAll("\\s", "");
    }

    public String resolveAttributeType(ObjectProperty attribute) {
        StringBuffer type = new StringBuffer("");
        if (attribute.isMultiple()) {
            if (attribute.getBag() != null && !"".equals(attribute.getBag())) {
                type.append(attribute.getBag());
            } else {
                type.append("java.util.List");
            }
            type.append("<");
        }
        type.append(attribute.getClassName());
        if (attribute.isMultiple()) {
            type.append(">");
        }
        return type.toString();
    }

    public String resolveAnnotationType(Annotation annotation) {
        StringBuffer type = new StringBuffer();
        AnnotationDefinition annotationDefinition = annotation.getAnnotationDefinition();

        if (annotationDefinition == null) {
            logger.warn("Annotation definition for annotation: " + annotation + " is not defined.");
            return type.toString();
        }

        if (annotationDefinition.isMarker()) {
            return type.toString();
        }

        //finally we can process annotation members.
        Object memberValue;
        int memberCount = 0;
        for (AnnotationValuePairDefinition memberDefinition : annotationDefinition.getValuePairs()) {
            if ((memberValue = annotation.getValue(memberDefinition.getName())) != null) {
                //a value has been set for this member.
                if (memberCount == 0) {
                    type.append("(");
                }
                if (memberCount > 0) {
                    type.append(", ");
                }
                type.append(resolveMemberType(memberDefinition, memberValue));
                memberCount++;
            }
        }
        if (memberCount > 0) {
            type.append(")");
        }

        return type.toString();
    }

    public String resolveMemberType(AnnotationValuePairDefinition valuePairDefinition, Object value) {
        StringBuffer type = new StringBuffer();

        type.append(valuePairDefinition.getName());
        type.append(" = ");
        type.append(resolveMemberTypeExpression(valuePairDefinition, value));
        return type.toString();
    }

    public String resolveMemberTypeExpression(AnnotationValuePairDefinition valuePairDefinition, Object value) {
        if (valuePairDefinition.isArray()) {
            return resolveMemberTypeArrayValue(valuePairDefinition, value);
        } else {
            return resolveMemberTypeValue(valuePairDefinition, value);
        }
    }

    public String resolveMemberTypeArrayValue(AnnotationValuePairDefinition valuePairDefinition, Object value) {
        if (value == null) {
            return null;
        }
        List<Object> values = (List<Object>) value;
        StringBuilder builder = new StringBuilder();
        builder.append("{");
        boolean isFirst = true;
        if (values.size() > 0) {
            for (Object listItem : values) {
                if (!isFirst) {
                    builder.append(", ");
                }
                builder.append(resolveMemberTypeValue(valuePairDefinition, listItem));
                isFirst = false;
            }
        }
        builder.append("}");
        return builder.toString();
    }

    public String resolveMemberTypeValue(AnnotationValuePairDefinition valuePairDefinition, Object value) {
        String typeValue = null;

        if (valuePairDefinition.isEnum()) {
            typeValue = resolveEnumValue(valuePairDefinition, value);
        } else if (valuePairDefinition.isString()) {
            typeValue = resolveStringValue(value);
        } else if (valuePairDefinition.isPrimitiveType()) {
            typeValue = resolvePrimitiveValue(valuePairDefinition, value);
        } else if (valuePairDefinition.isClass()) {
            typeValue = resolveClassValue(value);
        } else if (valuePairDefinition.isAnnotation() && value instanceof Annotation) {
            typeValue = "@"
                    + NamingUtils.normalizeClassName(valuePairDefinition.getAnnotationDefinition().getClassName())
                    + resolveAnnotationType((Annotation) value);
        }
        return typeValue;
    }

    public String resolveEnumValue(AnnotationValuePairDefinition valuePairDefinition, Object value) {
        if (value == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder();

        builder.append(NamingUtils.normalizeClassName(valuePairDefinition.getClassName()));
        builder.append(".");
        builder.append(value);
        return builder.toString();
    }

    public String resolveStringValue(Object value) {
        if (value == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        builder.append("\"");
        builder.append(escapeStringForJavaCode(value != null ? value.toString() : null));
        builder.append("\"");
        return builder.toString();
    }

    public String resolvePrimitiveValue(AnnotationValuePairDefinition valuePairDefinition, Object value) {

        if (value == null) {
            return null;
        }
        //primitive types are wrapped by the java.lang.type.
        StringBuilder builder = new StringBuilder();
        if (Character.class.getName().equals(valuePairDefinition.getClassName())) {
            builder.append("'");
            builder.append(value.toString());
            builder.append("'");
        } else if (Long.class.getName().equals(valuePairDefinition.getClassName())) {
            builder.append(value.toString());
            builder.append("L");
        } else if (Float.class.getName().equals(valuePairDefinition.getClassName())) {
            builder.append(value.toString());
            builder.append("f");
        } else if (Double.class.getName().equals(valuePairDefinition.getClassName())) {
            builder.append(value.toString());
            builder.append("d");
        } else {
            builder.append(value.toString());
        }
        return builder.toString();

    }

    public String resolveClassValue(Object value) {
        if (value == null) {
            return null;
        }
        StringBuilder builder = new StringBuilder();
        builder.append(value.toString());
        if (!builder.toString().endsWith(".class")) {
            builder.append(".class");
        }
        return builder.toString();
    }

    public String resolveSuperClassType(JavaClass javaClass) {
        StringBuffer type = new StringBuffer("");
        if (javaClass.getSuperClassName() != null && !"".equals(javaClass.getSuperClassName())) {
            type.append("extends ");
            type.append(javaClass.getSuperClassName());
        }
        return type.toString();
    }

    public String resolveImplementedInterfacesType(JavaClass javaClass) {
        StringBuilder type = new StringBuilder("implements " + Serializable.class.getName());

        if (javaClass.getInterfaces() != null) {
            for (String interfaceDefinition : javaClass.getInterfaces()) {
                if (interfaceDefinition.startsWith(Serializable.class.getName())) {
                    continue;
                }
                type.append(", ").append(interfaceDefinition);
            }
        }
        return type.toString();
    }

    public boolean hasSuperClass(DataObject dataObject) {
        return dataObject != null && dataObject.getSuperClassName() != null
                && !"".equals(dataObject.getSuperClassName());
    }

    public int keyFieldsCount(DataObject dataObject) {
        int count = 0;
        if (dataObject != null && dataObject.getProperties() != null && !dataObject.getProperties().isEmpty()) {
            for (ObjectProperty prop : dataObject.getProperties()) {
                if (DataModelUtils.isKeyField(prop)) {
                    count++;
                }
            }
        }
        return count;
    }

    public int propertiesCount(DataObject dataObject) {
        return (dataObject != null && dataObject.getProperties() != null) ? dataObject.getProperties().size() : 0;
    }

    public int enabledForConstructorPropertiesCount(DataObject dataObject) {
        int count = 0;
        if (dataObject != null && dataObject.getProperties() != null && !dataObject.getProperties().isEmpty()) {
            for (ObjectProperty prop : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(prop)) {
                    count++;
                }
            }
        }
        return count;
    }

    public boolean hasEquals(DataObject dataObject) {
        return keyFieldsCount(dataObject) > 0;
    }

    public boolean hasProperties(DataObject dataObject) {
        return propertiesCount(dataObject) > 0;
    }

    public boolean hasClassAnnotations(JavaClass javaClass) {
        return javaClass != null && javaClass.getAnnotations() != null && !javaClass.getAnnotations().isEmpty();
    }

    public boolean hasMethodAnnotations(Method method) {
        return method != null && method.getAnnotations() != null && !method.getAnnotations().isEmpty();
    }

    public String resolveMethodParameters(List<String> parameters) {
        StringBuilder builder = new StringBuilder("");
        Iterator<String> parameterIterator = parameters.iterator();
        int i = 1;
        while (parameterIterator.hasNext()) {
            builder.append(parameterIterator.next()).append(" o").append(i);
            if (parameterIterator.hasNext()) {
                builder.append(",");
            }
            i++;
        }
        return builder.toString();
    }

    public String buildMethodReturnTypeString(Type returnType) {

        if (returnType == null) {
            return null;
        }

        StringBuilder builder = new StringBuilder();

        builder.append(returnType.getName());

        buildTypeArgumentsString(returnType.getTypeArguments(), builder);

        return builder.toString();
    }

    public String buildMethodParameterString(List<Parameter> methodParameters) {
        if (methodParameters == null || methodParameters.isEmpty()) {
            return null;
        }

        StringBuilder builder = new StringBuilder();

        Iterator<Parameter> iterator = methodParameters.iterator();

        while (iterator.hasNext()) {
            Parameter parameter = iterator.next();

            Type parameterType = parameter.getType();
            builder.append(parameterType.getName());
            buildTypeArgumentsString(parameter.getType().getTypeArguments(), builder);
            builder.append(" ");
            builder.append(parameter.getName());

            if (iterator.hasNext()) {
                builder.append(",");
            }
        }

        return builder.toString();
    }

    private void buildTypeArgumentsString(List<Type> typeArguments, StringBuilder builder) {
        if (typeArguments == null || typeArguments.isEmpty()) {
            return;
        }
        builder.append("<");

        java.util.Iterator<Type> iterator = typeArguments.iterator();

        while (iterator.hasNext()) {
            Type argument = iterator.next();

            builder.append(argument.getName());

            buildTypeArgumentsString(argument.getTypeArguments(), builder);

            if (iterator.hasNext()) {
                builder.append(",");
            }
        }

        builder.append(">");
    }

    public String resolveEquals(DataObject dataObject, String indent) {

        StringBuilder head = new StringBuilder();
        //head.append(EOL);
        head.append(indent + "@Override" + EOL);
        head.append(indent + "public boolean equals(Object o) {" + EOL);
        head.append(indent + TAB + "if (this == o) return true;" + EOL);
        head.append(indent + TAB + "if (o == null || getClass() != o.getClass()) return false;" + EOL);
        head.append(
                indent + TAB + dataObject.getClassName() + " that = (" + dataObject.getClassName() + ")o;" + EOL);

        StringBuilder end = new StringBuilder();
        end.append(indent + "}");

        StringBuilder sb = new StringBuilder();

        List<ObjectProperty> props = DataModelUtils.filterKeyFields(dataObject);
        props = DataModelUtils.sortByFileOrder(props);

        boolean hasTerms = false;
        if (props != null && props.size() > 0) {
            for (ObjectProperty prop : props) {
                String _propName = toJavaVar(prop.getName());
                if (DataModelUtils.isKeyField(prop)) {

                    if (NamingUtils.isPrimitiveTypeId(prop.getClassName())) {
                        // Construction: "if (<_propName> != that.<_propName>) return false;
                        sb.append(indent + TAB);
                        addEqualsTermForPrimitive(sb, _propName, prop.getClassName());
                    } else {
                        // Construction: "if (<_propName> != null ? !<_propName>.equals(that.<_propName>) : that.<_propName> != null) return false;"
                        sb.append(indent + TAB + "if (");
                        sb.append(_propName).append(" != null ? !").append(_propName).append(".equals(that.")
                                .append(_propName).append(")");
                        sb.append(" : that.").append(_propName).append(" != null").append(") return false;");
                    }
                    sb.append(EOL);
                    hasTerms = true;
                }
            }
        }

        if (hasTerms) {
            sb.append(indent + TAB + "return true;" + EOL);
            head.append(sb);
            head.append(end);
            return head.toString();
        } else {
            return "";
        }
    }

    // for new template
    public String resolveEquals(DataObject dataObject) {
        return resolveEquals(dataObject, "");
    }

    private void addEqualsTermForPrimitive(StringBuilder sb, String _propName, String primitive) {
        if (NamingUtils.DOUBLE.equals(primitive)) {
            // if (Double.compare(that._double, _double) != 0) return false;
            sb.append("if (Double.compare(that.").append(_propName).append(", ").append(_propName)
                    .append(") != 0) return false;");
        } else if (NamingUtils.FLOAT.equals(primitive)) {
            // if (Float.compare(that._float, _float) != 0) return false;
            sb.append("if (Float.compare(that.").append(_propName).append(", ").append(_propName)
                    .append(") != 0) return false;");
        } else {
            // Construction: "if (<_propName> != that.<_propName>) return false;
            sb.append("if (").append(_propName).append(" != that.").append(_propName).append(")")
                    .append(" return false;");
        }
    }

    public String resolveHashCode(DataObject dataObject, String indent) {

        StringBuilder head = new StringBuilder();
        //head.append(EOL);
        head.append(indent + "@Override" + EOL);
        head.append(indent + "public int hashCode() {" + EOL);
        head.append(indent + TAB + "int result = 17;" + EOL);

        StringBuilder end = new StringBuilder();
        end.append(indent + "}");

        StringBuilder sb = new StringBuilder();

        List<ObjectProperty> props = DataModelUtils.filterKeyFields(dataObject);
        props = DataModelUtils.sortByFileOrder(props);

        boolean hasTerms = false;
        if (props != null && props.size() > 0) {
            for (ObjectProperty prop : props) {
                String _propName = toJavaVar(prop.getName());
                if (DataModelUtils.isKeyField(prop)) {

                    if (NamingUtils.isPrimitiveTypeId(prop.getClassName())) {
                        sb.append(indent + TAB);
                        addHashCodeTermForPrimitive(sb, _propName, prop.getClassName());
                    } else {
                        // Construction: "result = 13 * result + (<_propName> != null ? <_propName>.hashCode() : 0);"
                        sb.append(indent + TAB + "result = 31 * result + (").append(_propName).append(" != null ? ")
                                .append(_propName).append(".hashCode() : 0);");
                    }
                    sb.append(EOL);
                    hasTerms = true;
                }
            }
        }

        if (hasTerms) {
            sb.append(indent + TAB + "return result;" + EOL);
            head.append(sb);
            head.append(end);
            return head.toString();
        } else {
            return "";
        }
    }

    // for new template
    public String resolveHashCode(DataObject dataObject) {
        return resolveHashCode(dataObject, "");
    }

    private void addHashCodeTermForPrimitive(StringBuilder sb, String _propName, String primitive) {

        if (NamingUtils.BYTE.equals(primitive) || NamingUtils.CHAR.equals(primitive)
                || NamingUtils.SHORT.equals(primitive)) {
            //result = 31 * result + (int) _propName;
            sb.append("result = 31 * result + (int) ").append(_propName).append(";");
        } else if (NamingUtils.BOOLEAN.equals(primitive)) {
            //result = 31 * result + (_boolean ? 1 : 0);
            sb.append("result = 31 * result + (").append(_propName).append(" ? 1 : 0);");
        } else if (NamingUtils.LONG.equals(primitive)) {
            //result = 31 * result + (int) (_long ^ (_long >>> 32));
            sb.append("result = 31 * result + (int) (").append(_propName).append(" ^ (").append(_propName)
                    .append(" >>> 32));");
        } else if (NamingUtils.DOUBLE.equals(primitive)) {
            String temp = "Double.doubleToLongBits(" + _propName + ")";
            sb.append("result = 31 * result + (int) (" + temp + " ^ (" + temp + " >>> 32));");
        } else if (NamingUtils.FLOAT.equals(primitive)) {
            //"result = 31 * result + (_float != +0.0f ? Float.floatToIntBits(_float) : 0);"
            sb.append("result = 31 * result + (").append(_propName).append(" != +0.0f ? Float.floatToIntBits(")
                    .append(_propName).append(") : 0);");
        } else {
            //"result = 31 * result + _propName
            sb.append("result = 31 * result + ").append(_propName).append(";");
        }
    }

    public String resolveVisibility(Method method) {
        Visibility visibility = method.getVisibilty();

        if (visibility == null) {
            return "";
        }
        switch (visibility) {
        case PUBLIC:
            return "public";
        case PROTECTED:
            return "protected";
        case PACKAGE_PRIVATE:
            return "";
        case PRIVATE:
            return "private";
        default:
            throw new IllegalArgumentException("Visibility type '" + visibility + "' is not supported.");
        }
    }

    //TODO replace indent String with an integer that represents the indent level and get rid of duplicate methods (created not to affect existing adf)
    public String resolveAllFieldsConstructor(DataObject dataObject, String indent) {
        if (!dataObject.getProperties().isEmpty()) {
            List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
            for (ObjectProperty property : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(property)) {
                    sortedProperties.add(property);
                }
            }

            if (sortedProperties.size() > 0 && sortedProperties.size() < MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR) {
                //condition used by drools. All fields constructor is generated only if a class has less than
                // MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR
                return resolveConstructor(dataObject, DataModelUtils.sortByPosition(sortByName(sortedProperties)),
                        indent);
            }
        }
        return "";
    }

    // for new template
    public String resolveAllFieldsConstructor(DataObject dataObject) {
        if (!dataObject.getProperties().isEmpty()) {
            List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
            for (ObjectProperty property : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(property)) {
                    sortedProperties.add(property);
                }
            }
            if (sortedProperties.size() > 0 && sortedProperties.size() < MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR) {
                //condition used by drools. All fields constructor is generated only if a class has less than
                // MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR
                return resolveConstructor2(dataObject, DataModelUtils.sortByFileOrder(sortedProperties), "    ");
            }
        }
        return "";
    }

    public String resolveKeyFieldsConstructor(DataObject dataObject, String indent) {
        if (!dataObject.getProperties().isEmpty()) {
            List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
            for (ObjectProperty property : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(property) && DataModelUtils.isKeyField(property)) {
                    //the property is marked as key.
                    sortedProperties.add(property);
                }
            }
            if (sortedProperties.size() > 0 && sortedProperties.size() < dataObject.getProperties().size()) {
                return resolveConstructor(dataObject, DataModelUtils.sortByPosition(sortByName(sortedProperties)),
                        indent);
            }
        }
        return "";
    }

    // for new template
    public String resolveKeyFieldsConstructor(DataObject dataObject) {
        if (!dataObject.getProperties().isEmpty()) {
            List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
            for (ObjectProperty property : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(property) && DataModelUtils.isKeyField(property)) {
                    //the property is marked as key.
                    sortedProperties.add(property);
                }
            }
            if (sortedProperties.size() > 0 && sortedProperties.size() < MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR) {
                return resolveConstructor2(dataObject, DataModelUtils.sortByFileOrder(sortedProperties), "    ");
            }
        }
        return "";
    }

    // for new template
    public String resolvePositionFieldsConstructor(DataObject dataObject) {
        if (!dataObject.getProperties().isEmpty()) {
            List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
            for (ObjectProperty property : dataObject.getProperties()) {
                if (DataModelUtils.isAssignable(property) && DataModelUtils.isPositionField(property)) {
                    //the property is marked as key.
                    sortedProperties.add(property);
                }
            }
            if (sortedProperties.size() > 0 && sortedProperties.size() < MAX_FIELDS_FOR_DEFAULT_CONSTRUCTOR) {
                return resolveConstructor2(dataObject, DataModelUtils.sortByPosition(sortedProperties), "    ");
            }
        }
        return "";
    }

    public List<Annotation> sortAnnotationsByName(List<Annotation> annotations) {
        Collections.sort(annotations, new Comparator<Annotation>() {
            public int compare(Annotation o1, Annotation o2) {

                if (o1 == null && o2 == null) {
                    return 0;
                }
                if (o1 == null && o2 != null) {
                    return -1;
                }
                if (o1 != null && o2 == null) {
                    return 1;
                }

                Comparable key1 = o1.getClassName();
                Comparable key2 = o2.getClassName();

                if (key1 == null && key2 == null) {
                    return 0;
                }
                if (key1 != null && key2 != null) {
                    return key1.compareTo(key2);
                }

                if (key1 == null && key2 != null) {
                    return -1;
                }

                //if (key1 != null && key2 == null) return 1;
                return 1;
            }
        });
        return annotations;

    }

    public List<Annotation> sortedAnnotations(HasAnnotations hasAnnotations) {
        List<Annotation> sortedAnnotations = new ArrayList<Annotation>();
        if (hasAnnotations != null && !hasAnnotations.getAnnotations().isEmpty()) {
            sortedAnnotations.addAll(hasAnnotations.getAnnotations());
        }
        return sortAnnotationsByName(sortedAnnotations);
    }

    public List<ObjectProperty> sortedProperties(DataObject dataObject) {
        List<ObjectProperty> sortedProperties = new ArrayList<ObjectProperty>();
        if (dataObject != null && !dataObject.getProperties().isEmpty()) {
            sortedProperties.addAll(dataObject.getProperties());
        }
        return sortByName(sortedProperties);
    }

    public List<ObjectProperty> sortByName(List<ObjectProperty> properties) {
        Collections.sort(properties, new Comparator<ObjectProperty>() {
            public int compare(ObjectProperty o1, ObjectProperty o2) {

                if (o1 == null && o2 == null) {
                    return 0;
                }
                if (o1 == null && o2 != null) {
                    return -1;
                }
                if (o1 != null && o2 == null) {
                    return 1;
                }

                Comparable key1 = o1.getName();
                Comparable key2 = o2.getName();

                if (key1 == null && key2 == null) {
                    return 0;
                }
                if (key1 != null && key2 != null) {
                    return key1.compareTo(key2);
                }

                if (key1 == null && key2 != null) {
                    return -1;
                }

                //if (key1 != null && key2 == null) return 1;
                return 1;
            }
        });
        return properties;
    }

    public String resolveConstructor(DataObject dataObject, List<ObjectProperty> properties, String indent) {

        StringBuilder head = new StringBuilder();
        StringBuilder body = new StringBuilder();

        head.append(indent + "public " + dataObject.getName() + "(");

        if (properties != null && properties.size() > 0) {
            boolean isFirst = true;
            String propertyName;
            for (ObjectProperty property : properties) {
                if (!isFirst) {
                    head.append(", ");
                    body.append(EOL);
                }
                propertyName = toJavaVar(property.getName());
                head.append(resolveAttributeType(property));
                head.append(" ");
                head.append(propertyName);

                body.append(indent);
                body.append(indent);
                body.append("this.");
                body.append(propertyName);
                body.append(" = ");
                body.append(propertyName);
                body.append(";");

                isFirst = false;
            }
            body.append(EOL);
        }

        head.append(") {" + EOL);
        head.append(body);
        head.append(indent + "}");

        return head.toString();
    }

    // Same as above, but removed some indents that are not wanted for partial code adf purposes
    // TODO to be refactored
    public String resolveConstructor2(DataObject dataObject, List<ObjectProperty> properties, String indent) {

        StringBuilder head = new StringBuilder();
        StringBuilder body = new StringBuilder();

        head.append("public " + dataObject.getName() + "(");

        if (properties != null && properties.size() > 0) {
            boolean isFirst = true;
            String propertyName;
            for (ObjectProperty property : properties) {
                if (!isFirst) {
                    head.append(", ");
                    body.append(EOL);
                }
                propertyName = toJavaVar(property.getName());
                head.append(resolveAttributeType(property));
                head.append(" ");
                head.append(propertyName);

                body.append(indent);
                body.append("this.");
                body.append(propertyName);
                body.append(" = ");
                body.append(propertyName);
                body.append(";");

                isFirst = false;
            }
            body.append(EOL);
        }

        head.append(") {" + EOL);
        head.append(body);
        head.append("}");

        return head.toString();
    }

    public String escapeStringForJavaCode(String value) {
        if (value == null) {
            return value;
        }
        //we need to escape characters like this '\r\t', \n, and " to generate the code properly.
        return StringEscapeUtils.escapeJava(value);
    }

    public String fileHashEmptyTag() {
        return FileHashingUtils.getFileHashEmptyTag();
    }

    public String indent(String source) throws Exception {
        return START_INDENT + GenerationEngine.indentLines(source, LINE_INDENT);
    }

    public String indentFieldAnnotation(String source) throws Exception {
        return ANNOTATION_START_INDENT + "    " + source;
    }

    public String indentClassAnnotation(String source) throws Exception {
        return ANNOTATION_START_INDENT + source;
    }
}