

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.
|
|
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) |
|
|
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
|