Version: 2.1

Jindent

Jindent was originally written to format, in consideration of certain rules, any kind of Java source code to a new better formed output. Finally, these rules have been extended to be able to fulfill the most instructions of the Java Code Conventions provided by Sun, such as line wrapping, modificating white spaces, blank lines, inserting comments and so on. The different options of the rules can also be used to convert from one style of writing Java source codes to another.

Installation

To use Jindent, you need of course the Java Development Kit.
Jindent itself is a jar file, where all the needed classes and the property files are stored.
To install Jindent, just add the
Jindent.jar file, as usual, to your CLASSPATH.

In this version Jindent has three predefined property files which are already included in the Jindent.jar file:

Sun-Style.jin The current default property file for the Java Code Conventions defined by Sun.
C-Style.jin A property file of a C-style (only for demonstration)
Old-Style.jin A property file of an old Gnu style (only for demonstration)

Invoking Jindent

Actually there are two ways to use Jindent:

  • The standart Input/Output-mode: Jindent can read from the standart input and write also to the standart output.

java Jindent [options] < inputfile > outputfile

  • The file mode: Jindent can directly read its input from a file or a directory. After a successful formatting either the output will be written to a given destination directory (use -d) or it directly overwrites the original source file and a backup of the old file will be copied to inputfile.bak

java Jindent [options] -f[r] inputfile

The last mode is excellent for text editors, which allow command lines. Thus, Jindent can be used together with editors in an very easy way.

The command line options of Jindent are really few, because most of the rules and settings are stored in the property file.

Options:

-cr Use linefeed + carriage return (Windows/Dos)
-d path Set destination directory
-f inputfile Format inputfile and either write backup to inputfile.bak or write new files to given destination directory
-fr inputfile The same as -f, but check all subdirectories recursively too
-h Help for parameter usage (this)
-m Mute mode, if success then no output to console
(very useful for some text editors)
-p propertyname Set the Jindent property filename. If this option is not used, then automatically Jindent will use Sun-Style.jin as default. If a filename without any path is used, first, Jindent will look for it in its own "Jindent.jar" file, then in the current directory and finally in the user's home directory.
-w Print code modification warnings


An inputfile can be a normal filename, a given directory path or a filter. The filter function is very limited, it is only possible to use one "
* " and no " ? " in a choosen filter.

Examples:

java Jindent -f .\test\mySource.java

Format single given file and copy old file to .\test\mySource.java.bak. Settings of default property file Sun-Style.jin will be used.

java Jindent -p \My-Style.jin -fr "*.java" -d \newFiles

Format all java files in current directory and its subdirectories. Write all new files to directory \newFiles. If necessary the directory structure will be created first. Settings of property file \My-Style.jin will be used.

java Jindent -p C-Style.jin -fr "mySources\*.java"

Format all java files in mySources\ and its subdirectories and copy all backup files (*.java.bak) to the same directory structure. Settings of C-Style.jin property file (stored in Jindent.jar) will be used.

Property File

All necessary rules and settings to convert a Java sourcefile are stored in a property file. (This kind of property file should always have an extension of .jin)

Actually these stored entries can be handled like typical variables. They can be a type of boolean (true / false), integer (0, 1, 2, ... ) or string ("text").

for example:

booleanVariable = false

integerVariable = 2

stringVariable = "My text !"

There are already three predefined property files. The Sun-Style.jin, C-Style.jin and the Old-Style.jin. To know more about its settings you should extract them from the Jindent Jar-file and just read them to learn more about the different preferences. (For example it is always important to know the chosen tab size setting to use the same size in your text-editor !)

Of course it is possible to write own property files. We would suggest to use an original property file from the Jar-archive, rename it and try to change the settings to see the different behaviour of Jindent.

For detailed information please read the following chapters.

Note: It is important that all the following property variables appear in a Jindent property file. If any setting is missing then this will cause an error and Jindent would try to find an alternative value to go ahead.

A note for Jindent 2.0 beta user: It is not possible to use other property files from older Jindent versions.

Comments in Property Files

Comments should always start with ### to make them easy to recognize.

like:

### This is my personal Jindent Property File

				

Convention Note

Maybe it is necessary to add a note at the end of the source code, to be able to know if a formatting already has been done. This could be helpful for companies to see if an old source code is already formatted to the companies convention style or not.

For example, if you would like to add a note with the name "Acme Convention" then set:

setConventionNote = true
conventionName    = "Acme Convention"

and the last line of the source code would look like:

/*--- Formatting done in "Acme Convention" style on 04-08-1999 ---*/

Tabulators

It is possible to use either real tabs or just spaces.

Please notice: The tabulator size is NOT the same as the indent size.


To use real tabs set:

emulateTabs = false

To emulate Tabs with spaces:

emulateTabs = true


To set tabulator size to a typical integer number write for example:

tabulatorSize = 8

Indentation

The indentation can be one important part of a source code. It is not only related to different block levels, it also can be referred to other things, like comments or declarations.

If source code (for example in a block) will be indented, then Jindent uses the set indent size.

A good indentation can be:

indentSize = 4

For example, given a normal for-statement would then look like:

for (int i = 0; i < 10; i++) {
    System.out.println(i);
} 

If you would like to use tabs as an indent, then set indentSize and tabulatorSize to the same value and turn emulateTabs to false of course.


Furthermore it is possible to set a first level indentation. That would mean the beginning of the whole source code will be aligned to one kind of start column.

For example it can be useful to choose the same
firstLevelIndent and indentSize value.
Like:

firstLevelIndent = 4

If no first level indentation is needed then just turn the value to zero.

There are several conventions which use different styles of switch-case indentation. Jindent has an option to activate an indentation of case from its refering switch line:

indentCaseFromSwitch = true 

would produce the output:

switch(a) { 
    case 1:
        break;
    case 2:
        break;
    case 3:
        break;
    default:
} 

whereas:

indentCaseFromSwitch = false

would produce the output:

switch(a) { 
case 1:
    break;
case 2:
    break;
case 3:
    break;
default:
} 

A very useful way to change the style of source codes is to indent the identifiers of variable declarations:

indentDeclarations = true

will indent all variable identifiers to the same column:

String    s;
int       a, b; 
float     c, d, e; 
myOwnType f; 

To disable this, just use:

indentDeclarations = false 

the same code would look like:

String s;
int a, b;
float c, d, e;
myOwnType f; 

Note: The indentation of comments and declarations is related to each source code chunk. That means, in each chunk there will be a new column alignment of every indentation !

Jindent indents all comments within the same columns. At least as long as the comment line is still located in the boundaries of set line length.
Sometimes it is not possible to wrap lines as it should be. (see next chapter)
This can happen because of the non 'wrap-able' property of too long comment lines. However it is possible to indent these kind of comments by setting:

indentTooLongComments = true

Note: In some cases it is advisable to turn this option off to get a better formed output.

If real tabs are used, then it can be wise to indent comments and variable names at column values which are in easy reach by hitting tabs.
Therefore:

indentAlwaysAtTabColumn = true

uses indentation columns which are a multiple of the set tabulatorSize.


To control the indent of each comment related to code it is possible to set a minimum indent distance.

For example:

minimumCommentIndent = 4

Formating Braces

It is possible to control the appearance of all left braces "{" and right braces "}". Jindent can handle these braces in different ways. They can be set directly after a statement (typical java style) or just in an own line (more or less like C-style).

Additional it is possible to change the indentation before and after braces. These settings have an important effect to the appearance of a source code.

By combinating all these properties it is possible to gain a lot of different brace and source code styles:


For example - The typical Sun Java Style:

leftBraceNewLine       = false
rightBraceNewLine      = false
indentLeftBrace        = 1
indentRightBrace       = 0
indentAfterRightBrace  = 1

would look like:

if (a > 0) {
    a--;
} else {
    System.err.println("error...");
}

Or a different way - pseudo C-Style:

leftBraceNewLine       = true
rightBraceNewLine      = true
indentLeftBrace        = 0
indentRightBrace       = 0
indentAfterRightBrace  = 0

would cause:

if (a > 0) 
{
    a--;
}
else 
{ 
    System.err.println("error...");
} 

Or a combination of both:

leftBraceNewLine       = false
rightBraceNewLine      = true
indentLeftBrace        = 1
indentRightBrace       = 0
indentAfterRightBrace  = 0

Then:

if (a > 0) {
    a--;
}
else { 
    System.err.println("error...");
} 

Or a wild combination - old Gnu-Style:

leftBraceNewLine       = true
rightBraceNewLine      = true
indentLeftBrace        = 2
indentRightBrace       = 2
indentAfterRightBrace  = 0

would be:

if (a > 0)
  { 
    a--; 
  }
else
  { 
    System.err.println("error...");
  }

Note: In all these examples we suppose an indentation size of 4.


Finally it is also important to control empty braces.

cuddleEmptyBraces = false

would a source code make look like:

try {
    doSomething();
} catch (Exception e) {
}


Turning this setting on:

cuddleEmptyBraces = true

would the same source code making look like:

try {
    doSomething();
} catch (Exception e) {}

To get the full control of empty braces it is sometimes necessary to indent "cuddled braces" in a special way. In this case we used:

indentCuddledBraces = 1

Inserting Braces

Sometimes it can be helpful to insert braces at positions, where originally only single statements were used.

This can be controlled by the following switches:


If-Else Statements:

insertBracesAtIfElse = true

would change the given input:

if (a > 0)
    a--;
else
    System.err.println("error...");

to:

if (a > 0) {
    a--;
} else {
    System.err.println("error...");
}


For Statements:

insertBracesAtFor = true

would change the given input:

for (i = 0; i < 10; i++)
    System.out.println(i);

to:

for (i = 0; i < 10; i++) {
    System.out.println(i);
}


While Statements:

insertBracesAtWhile = true

would change the given input:

while (i < 10)
    i++;

to:

while (i < 10) {
    i++;
}


Do-While Statements:

insertBracesAtDoWhile = true

would change the given input:

do
    i++;
while (i < 10);

to:

do {
    i++;
} while (i < 10);

To keep the original appearance of a source code just set all settings to false.

Inserting and building JavaDocs

It is possible to create missing JavaDoc comments. They can be inserted before methods, constructors, classes and interfaces.


If JavaDoc Comments should be inserted then just set:

createMissingJavaDocs = true


To control and the building of new JavaDoc comments Jindent has several templates which allow a lot of variations.


A simple example for JavaDocs related to methods:

javaDoc_method_top[00]                 = "/**"
javaDoc_method_top[01]                 = " * Method declaration"
javaDoc_method_top[02]                 = " *"
javaDoc_method_param_separator[00]     = " *"
javaDoc_method_param[00]               = " * @param"
javaDoc_method_return[00]              = " *"
javaDoc_method_return[01]              = " * @return"
javaDoc_method_exception_separator[00] = " *"
javaDoc_method_exception[00]           = " * @throws"
javaDoc_method_bottom[00]              = " *"
javaDoc_method_bottom[01]              = " * @see"
javaDoc_method_bottom[02]              = " */"

Jindent distinguishes between top, param_separator, param, return, exception_separator, exception and bottom lines. It is possible to add dynamically till 100 lines (0-99) . But at least a line with number 0 has to be set.
If a JavaDoc comment is built then it starts at the beginning - with the top lines. Then it proceedes to the parameter part, which will only be printed if parameters appear in the method head. If this happens, then after finding the "
@param" keyword in the given param lines a space and then the parameter name will be inserted.
But first it starts with the param_separator to get a "break line" (or more) between the top and the params part to improve the general view of each JavaDoc.
Then, if necessary, the return part (keyword:
@return) will follow. After this, the exception part (all exceptions will be sorted) (keyword @exception or @throws) and finally always the bottom part.

Note: If no keywords are given in the templates then Jindent won't insert any information from any method head.


An example, using the previous settings to make it clear:

/**                                   // top 00
 * Method declaration.                // top 01
 *                                    // param separation 00
 * @param o                           // param 00
 * @param s                           // param 00
 *                                    // return 00
 * @return                            // return 01
 *                                    // exception separation 00
 * @throws myException                // exception 00
 *                                    // bottom 00
 * @see                               // bottom 01
 */                                   // bottom 02
public int print(int o, boolean s) throws myException;

Of course it is possible to have more space (lines) left for each param, exception, return or separation. Here another example:

javaDoc_method_top[00]                 = "/**"
javaDoc_method_top[01]                 = " * My Method"
javaDoc_method_param_separator[00]     = " *"
javaDoc_method_param[00]               = " * @param"
javaDoc_method_param[01]               = " *"
javaDoc_method_return[00]              = " *"
javaDoc_method_return[01]              = " * @return"
javaDoc_method_return[02]              = " *"
javaDoc_method_exception_separator[00] = " *"
javaDoc_method_exception_separator[01] = " *"
javaDoc_method_exception_separator[02] = " *"
javaDoc_method_exception[00]           = " * @throws"
javaDoc_method_exception[01]           = " *"
javaDoc_method_bottom[00]              = " *"
javaDoc_method_bottom[01]              = " *"
javaDoc_method_bottom[02]              = " */"

would cause:

/**                                   // top 00
 * My Method                          // top 01
 *                                    // param separation 00
 * @param o                           // param 00
 *                                    // param 01
 * @param s                           // param 00
 *                                    // param 01
 *                                    // return 00
 * @return                            // return 01
 *                                    // return 02
 *                                    // exception separation 00
 *                                    // exception separation 01
 *                                    // exception separation 02
 * @throws myException                // exception 00
 *                                    // exception 01
 *                                    // bottom 00
 *                                    // bottom 01
 */                                   // bottom 02
public int print(int o, boolean s) throws myException;


If any kind of line won't be needed (for example no separations) then just use:

javaDoc_method_param_separator[00] = ""

And this line won't appear in any JavaDoc.


JavaDocs of constructors have the same kind of templates like methods. Only interfaces and classes are much easier to handle. To learn more about them just have a look in the property files.

Controlling JavaDocs and General Comments

If it is necessary to keep already written JavaDoc comments of the original source, use the following setting:

ignoreJavaDocs = false

To ignore all old JavaDoc comments, set:

ignoreJavaDocs = true

For example, if the setting ignoreJavaDocs = true is combined with createMissingJavaDocs = true then all old JavaDocs will be overwritten with the new generated one. Of course it is also possible to mix the old with the new one, by using the settings ignoreJavaDocs = false and createMissingJavaDocs = true.

Besides JavaDoc comments, Jindent knows two other types of comments. First Multi Line Comments, which are comments using more than one line, like:

/*
 * Multi
 * Line
 * Comment
 */

And secondly a Single Line Comment, which only needs one line, like:

// single line comment

Or:

/* Different Style, but also single line comment ! */

Just as controlling the JavaDoc comments (see above), it is possible to control
the appearance of these kind of comments too.

All Multi Line and Single Line Comments will be ignored by using:

ignoreMultiLineComments   = true
ignoreSingleLineComments  = true

Blank Lines

Blank lines in a source code are necessary to separate statements or declarations with different functions or meanings. Jindent has several options to control blank lines.
The normal way is to use an integer type to give the number of needed blank lines.
If no blank lines are needed then simply turn it to zero.

One blank line after variable declarations will follow with this setting:

blankLineAfterDeclarations = 1

An example output could look like:

void myMethod() {
    char s[];
    int a, b, c;

    System.out.println("Hello World !");
    ...
}

A blank line after a method will follow with this setting:

blankLineAfterMethods = 1

This could lead an example to:

class myClass {
    void MethodA() {
        doSomething();
    }

    void MethodB() {
        doAnything();
    }

}

A way to separate an interface from a class declaration or vice versa is to use the following option.

In this case Jindent will insert two blank lines between them:

blankLinesBetweenClassInterface = 2

will make a sample source look like this:

interface myInterface {
    ...
}


class myClass {
    ...
}


Sometimes it can be neccessary to separate several parts which have logical differences. (Not only like variable declarations or classes and interfaces.) In this case, it is possible to use the following option

For the input:

public class myClass {                       
    float a, b, c;                              // Declaration
    int d, e;                                   // Declaration
    public void main() {                      
        String g;                               // Declaration
        System.out.println("Hello World !");    // Function call
        myFunction();                           // Function call
        d = bla();                              // Assingment
        b = c + 1;                              // Assingment
        e = (a < 10);                           // Assingment
    }
}

the setting:

blankLinesBetweenChunks = 1

would lead to:

public class myClass {                       
    float a, b, c;                              // Declaration
    int d, e;                                   // Declaration

    public void main() {                      
        String g;                               // Declaration

        System.out.println("Hello World !");    // Function call
        myFunction();                           // Function call

        d = bla();                              // Assingment
        b = c + 1;                              // Assingment
        e = (a < 10);                           // Assingment
    }
}

By the way, in the same way Jindent defines Chunks internally.


A good way to increase the attention of comments is to insert a blank line before a comment, after a comment or both. This can be easily handled by using the following settings:

blankLinesBeforeSingleComments = 1

Example:

int a, b, c;

// Code starts here
System.out.println("Hello World !"); 


Or a blank line after a single line comment:

blankLinesAfterSingleComments = 1


Example:

int a, b, c;
// Code starts here

System.out.println("Hello World !");


Otherwise no blank lines are inserted. Analogous settings to previous examples are:

blankLinesBeforeMultiComments  = 1
blankLinesAfterMultiComments   = 1
blankLinesBeforeJavaDocs       = 1
blankLinesAfterJavaDocs        = 1

 

All these precending examples insert new blank lines into the given input source code, but of course it is also possible to keep all old blank lines:

keepBlankLines = true

 
A very interesting way is to combine all settings. Jindent wouldn't add blank lines to already existing original blank lines, thus it is more or less the same as the "OR" combination related to bits.

Whitespaces

Whitespaces can be handled in a similar way as blank lines. But in this case Jindent only allows boolean values.

It is possible to insert a space before and after operators to separate it from the rest of the source code.

Assigment operators are
=, +=,*=... for this use:

separateAssignmentOperators = true


Conditional operators are
&&, ||,... for this use:

separateConditionalOperators = true


Comparison operators are
<, >, !=... for this use:

separateComparisonOperators = true


Numerical operators are
+, -, &, ^... for this use:

separateNumericalOperators = true



Consider
separateAssignmentOperators is turned to false and separateNumericalOperators is turned to true, then an example could look like:

a=(b + c) / d;
f=a - b;


To insert a space after a comma use:

spaceAfterComma = true


The same after semicolon (this is actually only necessary for For-Statements):

spaceAfterSemicolon = true


Space after castings:

spaceAfterCasting = true


To insert a space before the left parenthesis in a method call or method head:

spaceBeforeMethodParameters = true


The same for java statments (like:
while, catch, if, ...) :

spaceBeforeStatementParameters = true


Padding in this case means to insert a space after left parenthesis "
(" and a space before right parenthesis ")". To activate this function use:

paddingParenthesis = true

The same for left brackets "[" and right brackets "]":

paddingBrackets = true

Suppose all padding-settings are turned to true, then an example output would look like:

a[ x*10 ][ y ] = b*( 100/x )+( 100/y );

Line Wrapping

Line Wrapping can be one of the most important part of source code formatting. There are always a lot of ways to wrap a line. Jindent knows several methods and always tries to find the best solution. It tries to keep attention of operator precedence, prefer low level wrapping and so on. But there are still a lot of settings to configure a proper line wrapping. The setting:

wrapLines = true 

will turns the line wrapping mode on. Example:

x = (y * 100) + 42
    + (100 - z); 

To turn the mode off set:

wrapLines = false 

and the same line would look as usual:

x = (y * 100) + 42 + (100 - z); 

If the line wrapping mode is used, then it is of course necessary to set the maximum line length. The setting:

maxLineLength = 78 

limits the line length to 78 characters.

It is possible to control a line with a very long comment whether it should be wrapped or not. By using this option it is possible to decide if the focus should be on the pure java code or on the code including all comments. The setting:

wrapBecauseOfComments = true

could lead to the following output:

value = function(param1, param2, 
                 param3);    // My long Comment 

Jindent tries to keep the comment in the set line limit.
Whereas

wrapBecauseOfComments = false 

would format the same line like:

value = function(param1, param2, param3);   // My long Comment 

Long package names and class names can cause very long method invokations. It is possible to force a wrapping of these names:

wrapLongMethodNames = true 

An example could look like:

x = my.very.long.function.name
    .with.a.lot.of.stupid.dots(); 

Sometimes Jindent may decide to wrap lines in a correct, but not very good looking way. For example:

void myVeryLongMethodName(int paramOne) throws ExceptionOne, 
                                               ExceptionTwo,
                                               ExceptionThree { 
    myFirstCode(); 
    ...
} 

This is a bad behaviour which should be avoided. In this case we define a variable which only allows a certain lenght of these kind of gaps. Then Jindent would try to find an alternative solution:

deepIndent = 45

causes Jindent to avoid deep indentation above the 45th column:

void myVeryLongMethodName(int paramOne) 
    throws ExceptionOne, ExceptionTwo, ExceptionThree { 
    myFirstCode(); 
    ... 
} 

Unfortunatly the method myFirstCode() is now easy to miss, because the wrapped line and the first line of the method body are indented to the same column. To prevent this it is possible to set a tolerance and a correction value. The setting:

forceIndentTolerance = 3 

will correct all wrapped lines which have a distance to the tab settings between -3 and 3. In our example the line had a distance of 0. Wrapped lines which have indentation problems will just indent to a certain value which is controlled by this variable:

forceIndent = 8

This would make the same example look like:

void myVeryLongMethodName(int paramOne)
        throws ExceptionOne, ExceptionTwo, ExceptionThree { 
   myFirstCode();
   ...
}

Now, the first line won't be missed anymore.


If a "force indent" option isn't needed then it is possible to turn it off by using:

forceIndentTolerance = -1

For example, it is not necessary to "force" such an indentation if the leftBraceNewLine option is turned to true.

Labels

Actually there are only two general ways to handle labels:

labelNewLine = false

Could cause an output:

myLabel: while (a < 10) {
   ...
   break myLabel;
   ...
}

To separate the appearance of the labels use:

labelNewLine = true

Would change the same to:

myLabel:
while (a < 10) {
   ...
   break myLabel;
   ...
}

          

Jindent's Interface For Code Generation

Jindent has an internal interface for its code generation. Of course it is possible to access from an own source code to this kind of interface. We know this interface is not helpful in all cases, so we will publish a better one in the next Jindent version (Please read chapter "Planned Features".)

Including to the Jindent.jar file we have published a short demo source code called InterfaceDemo.java to show the usage of this interface.

Planned Features

We are planning to develop a next version of Jindent which will probably be published in the 3rd quarter of 1999.

The following features will be implemented:

  • Optional sorting and separating of package names in import declarations.

  • A new mode for html output. Thus, Jindent will be able to generate automatically html pages including syntax highlighting, hyber links to jump from one source code part to another (similar to JavaDocs).

  • A new and better interface for code generation, which will allow user to stream an own generated inputstream into Jindent and get an outputstream with a better formated output. In this way, Jindent will become a helpful class for programmers who need to generated their own java source code.

Final Words

Please help to develope and improve this program and send all found bugs, suggestions or new ideas to our email address:

jindent@c-lab.de

And do not forget to check our web site regularly for the latest version of Jindent at:

http://www.c-lab.de/~jindent