Wednesday, July 04, 2007

Eclipse: project specific checkstyle configuration

Updates:
- 12th July, 2007 - use "Project Relative Configuration", don't use absolute paths.
- 21st March, 2008 - Modified JavadocMethod and RedundantThrows checks in checkstyleRules.xml (on box.net) as per this note.
- 24th May, 2009 - Modified linked checkstyleRules.xml (on box.net): a) sorted modules by name; b) added modifications I referred to in my first comment below.
- 28th February, 2010 - re-wrote post to use generated Checkstyle.xml and extra detail about customisation.
- 17th March, 2013 - Checkstyle Configuration now also in this pastebin: http://pastebin.com/hz77H62W

This is how I set up project specific Checkstyle configuration as files that you check in to source control so that every developer who works on the project will automatically use the same Checkstyle rules. This post assumes your team is using Eclipse (3 or greater) and has the Checkstyle plugin installed. Two files are involved: [projectRoot]/.checkstyle and checkstyle.xml. Eclipse projects with Checkstyle enabled will use a file called .checkstyle (in the project root dir) to record Eclipse specific checkstyle configuration settings and I always save the Checkstyle XML rules to [projectRoot]/tools/ide/checkstyle/checkstyle.xml..

Create a Checkstyle configuration for your project in the following way.

  1. Remove previous configurations and file sets.
    1. Select Project | Properties | Checkstyle | Main tab.
    2. If "Checkstyle active for this project" is not ticked, skip this step (Remove previous configurations...).
    3. Make sure "Use simple configuration" is not ticked.
    4. Un-tick "Enabled" and click Remove for any File Set entries in the top section (labeled "Advanced - configure file sets ...").
    5. Switch to the "Local Check Configurations" tab.
    6. Remove any "Check Configuration" entries you see there.
    7. Press "OK" to exit Project Properties.
  2. Generate the checkstyle XML rules file.
    1. In your project, make a directory like tools\ide\checkstyle or whatever makes sense to you.
    2. In Eclipse select Windows | Preferences | Checkstyle | select "Sun Checks (Eclipse" under "Global Check Configurations" | click Export | export to checkstyle.xml in the tools\ide\checkstyle directory (name and location can be anything, as long as it's in the project somewhere and has a name that makes sense).
  3. Set checkstyle.xml as your project local checkstyle configuration.
    1. Select Project | Properties | Checkstyle | Local Check Configurations.
    2. Press "New" and you should see the "Check Configuration Properties" dialog.
    3. Under "Type", select "Project Relative Configuration".
    4. Enter "Name" as "Local PROJECT X Checkstyle Configuration".
    5. Click "Browse" and navigate to your project's checkstyle xml file.
    6. Press "OK".
    7. Switch to the Main tab.
    8. If "Checkstyle active for this project" is not ticked, tick it.
    9. If "Use simple configuration" is not ticked, tick it. (See note on custom file sets below for more detail on this.
    10. In the drop down, select the "Local PROJECT X Checkstyle Configuration" you created earlier.
    11. Press "OK".
    12. Press "OK" (again).
    13. In the "Rebuild suggested" dialog, press "Yes".

Custom file sets. It is possible to use different Checkstyle rules (a different XML file) for different sets of Java files. For example, maybe you want to use more relaxed Checkstyle rules for your test cases (pesky Magic Numbers!). This is not hard to set up but it is harder to manage multiple Checkstyle Configurations than just one when things change. To use custom file sets, see below.

  1. Make a copy of checkstyle.xml for each file set you intend to use. Edit each XML as appropriate to apply the rules you want (see the note on customising checkstyle rules below.
  2. Create a Checkstyle Configuration for each file set (Project | Properties | Checkstyle | Local Check Configurations | New ...).
  3. Select Project | Properties | Checkstyle | Main.
  4. If "Checkstyle active for this project" is not ticked, tick it.
  5. If "Use simple configuration" is ticked, un-tick it.
  6. For each file set, press "Add" and fill out the "Checkstyle File Set Editor" dialog.
  7. Under "File Set Name" enter "PROJECT X Checkstyle File Set - [main, test, whatever]".
  8. Under "Check Configuration", select the Checkstyle Configuration you created earlier for this specific file set.
  9. Modify the regular expression patterns to define what files this Checkstyle Configuration should apply to. There is content assist to help building the regular expressions.

Personally, I have never had a real need for multiple Checkstyle configurations. I have just one configuration and use SuppressionCommentFilter to turn off Checkstyle in annoying chunks of test code (// CHECKSTYLE:OFF ... // CHECKSTYLE:ON.

Customising checkstyle rules. You can modify the rules in two ways: through Eclipse or by editing the XML file.

To edit them through Eclipse, select Project | Properties | Checkstyle | Local Check Configurations | click the one to edit | click Configure. On the left side you see categories of Checkstyle rules (Annotations, Javadoc Comments etc). Click on a category and you see over to the right side which individual rules for that category you are currently using. Tick or un-tick rules to use/ignore them. Click "Open" on any rule to modify the selected rule (there is a lot of room for customisation). Notice the icons on the left have a green tick if they are being used. Sometimes you don't see the item (ticked or not) on the right hand side. Click on it on the left had side and then click Add to use it (which also opens the customisation dialog which you have to accept). You see helpful notes against each item in the Description field, but sometimes it can be tricky working out which rule is the one you are after.

Whatever you do, don't select all on the left side and then click "Add". Eclipse makes you respond to every single customisation dialog for every single checkstyle rule, and I do believe there is an infinite number of them. I had to kill Eclipse and learn my lesson.

To edit them through the XML file, you need to... erm, edit the XML file. Refer to the Checkstyle Documentation for assistance. Each page has helpful (though at times sparse) examples.

As long as the plugin is installed, checkstyle will now work "out of the box" for any new developers.

Below is an example .checkstyle (xml) created for a project using the above process.

<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="true">
    <local-check-config name="Local PROJECT X Checkstyle Configuration" location="tools/checkstyle/checkstyleRules.xml" type="project" description="">
        <additional-data name="protect-config-file" value="false"/>
    </local-check-config>
    <fileset name="all" enabled="true" check-config-name="Local PROJECT X Checkstyle Configuration" local="true">
        <file-match-pattern match-pattern="." include-pattern="true"/>
    </fileset>
</fileset-config>

You can also look at a sample Checkstyle xml file, checkstyleRules.xml (on box.net). Warning: this is valid under Checkstyle 4, but not 5 or later, where some schema changes were made - though most of the XML for individual rules should still be valid.

1 comment:

RobertMarkBram said...

Use these to stop errors appearing from Checkstyle choking on exceptions:
Method Javadoc: Unable to get class information for @throws tag 'SomeExceptionName'

<module name="JavadocMethod">
<property name="logLoadErrors" value="true"/>
<property name="suppressLoadErrors" value="true"/>
</module>

<module name="RedundantThrows">
<property name="logLoadErrors" value="true"/>
<property name="suppressLoadErrors" value="true"/>
</module>

Use these to allow spaces around generics declarations.

<module name="NoWhitespaceAfter">
<!-- Default tokens and additional GENERIC_START -->
<property name="tokens"
value="ARRAY_INIT, BNOT, DEC, DOT, INC, LNOT, UNARY_MINUS, UNARY_PLUS, GENERIC_START" />
</module>
<module name="NoWhitespaceBefore">
<!-- Default tokens and additional GENERIC_START and GENERIC_END -->
<property name="tokens"
value="SEMI, POST_DEC, POST_INC, GENERIC_START, GENERIC_END" />
</module>
<module name="WhitespaceAfter">
<!-- Default tokens and additional GENERIC_END -->
<property name="tokens" value="COMMA, SEMI, TYPECAST, GENERIC_END" />
</module>
<module name="WhitespaceAround">
<!-- Default tokens without GENERIC_START and GENERIC_END -->
<property name="tokens"
value="ASSIGN, BAND, BAND_ASSIGN, BOR,
BOR_ASSIGN, BSR, BSR_ASSIGN, BXOR, BXOR_ASSIGN, COLON, DIV,
DIV_ASSIGN, EQUAL, GE, GT, LAND, LCURLY, LE, LITERAL_ASSERT,
LITERAL_CATCH, LITERAL_DO, LITERAL_ELSE, LITERAL_FINALLY,
LITERAL_FOR, LITERAL_IF, LITERAL_RETURN, LITERAL_SYNCHRONIZED,
LITERAL_TRY, LITERAL_WHILE, LOR, LT, MINUS, MINUS_ASSIGN, MOD,
MOD_ASSIGN, NOT_EQUAL, PLUS, PLUS_ASSIGN, QUESTION, RCURLY, SL,
SLIST, SL_ASSIGN, SR, SR_ASSIGN, STAR, STAR_ASSIGN,
TYPE_EXTENSION_AND, WILDCARD_TYPE" />
</module>