Foreword

This document describes a list of coding conventions that are required for code submissions to AndroMDA. By default, coding conventions for most Open Source Projects should follow the existing coding conventions in the file that you are working on. For example, if the bracket is on the line after the if statement, then you should write all your code to have that convention.

AndroMDA Developer Coding Conventions

Below is a list of coding conventions that are specific to AndroMDA. Anything else not specifically mentioned here should follow the official Sun Java Coding Conventions.

General Coding Conventions

The following applies to any code, whether it be templates, java files, XML files, etc.

  • Indentations: 4 spaces. NO tabs. Period. We understand that a lot of you like to use tabs, but the fact of the matter is that in a distributed development environment, when the svn commit messages get sent to a mailing list, they are almost impossible to read if you use tabs.

    Another requirement is to set the right margin to 120 characters, so lines break if they exceed this limit. A shorter limit is not acceptable since it will break lines sooner and will disrupt the look and feel of the code.

Java Coding Conventions

  • Brackets: All brackets (class, method, if, try, etc) must begin and end on a new line. Example :

    public class SomeClass
    {
        public void someMethod()
        {
            if (xxx)
            {
            }
        }
    }
    
  • Whitespace: No extra trailing whitespace at the end of a line. Do not add extra whitespace around parenthesis (i.e. "if ( this.isComposition() )") or casts ("(ClassifierFacade) element"), instead they should be written written like the following:

    if (this.isComposition()) 
    {
    }
                            
    ClassifierFacade classifier = (ClassifierFacade)element;
                            
  • Collections: Always use strongly-typed Collections whenever possible. This detects type errors at compile time instead of at runtime, which is much easier to debug and fix, and automatically flags incorrectly implemented methods. In cartridges using UML2 models, use multiplicity * referring to the target Class, rather than the generic List or Collection types, for all attributes/associations/parameters. All casting problems will be flagged as compiler warnings in every build. If calling a non-typesafe underlying method that cannot be modified, add

    @SuppressWarnings("unchecked")
                            
  • Iterators: Use Java5 for (VariableType variable : variableList()) loops instead of Iterator whenever possible (i.e. not altering the itrated value within the loop). This reduces the amount if code, eliminated type-casting, and is easier to understand. If looping using an iterator, do these in for-loops instead of while loops (because this allows the iterator itself to be scoped into that block). Example:

    for (final Iterator stereotypeIterator = stereotypes.iterator(); stereotypeIterator.hasNext();)
    {
        final ModelElement stereotype = (ModelElement)stereotypeIterator.next();
        stereoTypeNames.add(stereotype.getName());
    } 
  • Comments: Javadoc SHOULD exist on all your class members (methods + class variables), including the protected and private ones. Also, if you are working on existing code and there currently isn't a javadoc for that method/class/variable or whatever, then you should contribute and add it. This will improve the project as a whole. Also add code comments when you think it's necessary (like assumptions), especially when the code is not obvious. Document WHY the code is doing something, not what it is doing unless the operation sequence is very complex (consider refactoring).

  • Author References: If you contribute to a file (code or documentation), add yourself to the top of the file (below the existing authors). For java files the preferred Javadoc format is:

    @author FirstName LastName
                            
  • Exiting Methods: There should be only a single point of exit out of a method (i.e. a single return statement).

    public int getEntityCount()
    {
        // don't do this:
        /*
            if (condition)
            {
               return 6;
            }
            return 0;
        */
    
        // but do this:
        int entityCount = 0;
    
        if (condition)
        {
            entityCount = 6;
        }
    
        return entityCount;
    } 
  • Variable Names: attr should be written as attribute, collIdents should be identifiers (the type is Collection, don't specify that in the name), the code should read as plain English.

  • Instance Variables: Instance variables should not have any prefix and must be referenced using the this object. Example :
    public class SomeClass
    {
        private String someString;
        ...
        public void someMethod()
        {
            logger.debug("Value = " + this.someString);
        }
    } 
  • Parameter: Method parameter names should not have any prefix indicating the type (strClassName for a String). When more than one parameter is present in the list we write each one of them on a new line and indent. Where possible we make the parameter final. For example :
    public void someMethod(
        final String className,
        final int count)
    {
    } 
  • Strings: Avoid hardcoding values, Strings as well as numbers, etc should go into a properties file or a class holding constants.

  • Imports: Use fully qualified import names when importing classes, this makes it easier for users not familiar with the code base to see where classes are coming from.

  • Switch/case: Switch/case constructs look like this (please respect the indentation). When ever a break keyword would be missing it should be replaced by a comment indicating the fall-through. If the default action is to not perform anything then please put this in a comment so people know it's on purpose.

    switch(myValue)
    {
        case 1 :
            doSomething();
            break;
        case 2 :
            doSomething2();
            break;
        case 3 :    // fall-through
        case 4 :
            doSomethingElse();
            break;
        default :
            // do nothing
    }
                                
  • Logging: Do NOT use System.out.println() for debugging purposes in your code, instead use a log4j logger.

    try
    {
       ...
    }
    catch (Exception ex)
    {
        logger.error("Some error has occurred" + ex);
    }
                            
  • Exception Recording: Do NOT use ex.printStackTrace() for debugging purposes in your code, instead use the provided ExceptionRecorder class.

    try
    {
       ...
    }
    catch (Exception ex)
    {
        logger.error("Some error has occurred" + ex);
        ExceptionRecorder.instance().record( ex );
    }
                            

    This will create a .exc file with the stacktrace and additional debugging and environment information:

    ------- AndroMDA Exception Recording -------
    Version ........: 3.5-SNAPSHOT
    Error ..........: Error performing ModelProcessor.process with model(s) --> 'C:/Windows/1Workspaces/A34/andromda-all/andromda-documentation/samples/timetracker/mda/src/main/uml2/timetrackerBad.uml'
    Build ..........: ${buildNumber}
    Build System ...: Windows 7.0
    Build JDK ......: Sun Microsystems Inc.-17.0-b16
    Build Builder ..: RJF3
    Run System .....: Windows 7.0
    Run JDK ........: Sun Microsystems Inc.17.0-b16
    Main Exception .: org.andromda.core.metafacade.MetafacadeFactory.createMetafacade - 'mappingObject' can not be null
    Root Exception .: java.lang.IllegalArgumentException: org.andromda.core.metafacade.MetafacadeFactory.createMetafacade - 'mappingObject' can not be null
    java.lang.IllegalArgumentException: org.andromda.core.metafacade.MetafacadeFactory.createMetafacade - 'mappingObject' can not be null
        at org.andromda.core.common.ExceptionUtils.checkNull(ExceptionUtils.java:67)
                            

Template Coding Conventions

  • Referencing properties: In Velocity (etc) try to do $variable.property instead of $variable.getProperty(), the two calls are equivalent but the former better matches our metamodels (and is less code to write).

Committing Code into SVN

  • As always, make sure to have a clear comment supporting your change in SVN, if something goes wrong others might help to track down the problem by reading the history.

  • If you fixed, added, updated or removed a feature then update /src/changes/changes.xml. Take a look at previous changes for examples.

Submitting Patches

As always, use JIRA to submit feature requests and patches.

If you have modified your local version by adding a new feature and would like to see in the main distribution, then file a new issue in JIRA and attach the patch to it (please do not send it to the mailing list).

If you want to see your patch quickly applied by committers, you should be able to provide the following items:

  1. A patch file (this can be very easily created if you're using eclipse) against the latest SVN version. No, a zip file with all modified sources is *not* okay.
  2. If appropriate, include one or more JUnit tests related to the new feature. Also, be sure to run all of the existing testcases to verify that you are not breaking existing code.
  3. Where applicable, update the documentation (namespace/modeling docs, samples, ...).

If all of these requirements are met and you are respecting the coding conventions, then it is very likely your patch will be accepted soon.