Class CustomImportOrderCheck
- java.lang.Object
-
- com.puppycrawl.tools.checkstyle.api.AutomaticBean
-
- com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter
-
- com.puppycrawl.tools.checkstyle.api.AbstractCheck
-
- com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck
-
- All Implemented Interfaces:
Configurable,Contextualizable
public class CustomImportOrderCheck extends AbstractCheck
Checks that the groups of import declarations appear in the order specified by the user. If there is an import but its group is not specified in the configuration such an import should be placed at the end of the import list.
The rule consists of:1. STATIC group. This group sets the ordering of static imports.
2. SAME_PACKAGE(n) group. This group sets the ordering of the same package imports. Imports are considered on SAME_PACKAGE group if n first domains in package name and import name are identical.
package java.util.concurrent.locks; import java.io.File; import java.util.*; //#1 import java.util.List; //#2 import java.util.StringTokenizer; //#3 import java.util.concurrent.*; //#4 import java.util.concurrent.AbstractExecutorService; //#5 import java.util.concurrent.locks.LockSupport; //#6 import java.util.regex.Pattern; //#7 import java.util.regex.Matcher; //#8If we have SAME_PACKAGE(3) on configuration file, imports #4-6 will be considered as a SAME_PACKAGE group (java.util.concurrent.*, java.util.concurrent.AbstractExecutorService, java.util.concurrent.locks.LockSupport). SAME_PACKAGE(2) will include #1-8. SAME_PACKAGE(4) will include only #6. SAME_PACKAGE(5) will result in no imports assigned to SAME_PACKAGE group because actual package java.util.concurrent.locks has only 4 domains.
3. THIRD_PARTY_PACKAGE group. This group sets ordering of third party imports. Third party imports are all imports except STATIC, SAME_PACKAGE(n), STANDARD_JAVA_PACKAGE and SPECIAL_IMPORTS.
4. STANDARD_JAVA_PACKAGE group. By default this group sets ordering of standard java/javax imports.
5. SPECIAL_IMPORTS group. This group may contains some imports that have particular meaning for the user.
NOTE!
Use the separator '###' between rules.
To set RegExps for THIRD_PARTY_PACKAGE and STANDARD_JAVA_PACKAGE groups use thirdPartyPackageRegExp and standardPackageRegExp options.
Pretty often one import can match more than one group. For example, static import from standard package or regular expressions are configured to allow one import match multiple groups. In this case, group will be assigned according to priorities:
- STATIC has top priority
- SAME_PACKAGE has second priority
- STANDARD_JAVA_PACKAGE and SPECIAL_IMPORTS will compete using "best match" rule: longer matching substring wins; in case of the same length, lower position of matching substring wins; if position is the same, order of rules in configuration solves the puzzle.
- THIRD_PARTY has the least priority
Few examples to illustrate "best match":
1. patterns STANDARD_JAVA_PACKAGE = "Check", SPECIAL_IMPORTS="ImportOrderCheck" and input file:
import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck;Result: imports will be assigned to SPECIAL_IMPORTS, because matching substring length is 16. Matching substring for STANDARD_JAVA_PACKAGE is 5.
2. patterns STANDARD_JAVA_PACKAGE = "Check", SPECIAL_IMPORTS="Avoid" and file:
import com.puppycrawl.tools.checkstyle.checks.imports.AvoidStarImportCheck;Result: import will be assigned to SPECIAL_IMPORTS. Matching substring length is 5 for both patterns. However, "Avoid" position is lower then "Check" position.
Properties:name Description type default value customImportOrderRules List of order declaration customizing by user. string null standardPackageRegExp RegExp for STANDARD_JAVA_PACKAGE group imports. regular expression ^(java|javax)\. thirdPartyPackageRegExp RegExp for THIRD_PARTY_PACKAGE group imports. regular expression .* specialImportsRegExp RegExp for SPECIAL_IMPORTS group imports. regular expression ^$ separateLineBetweenGroups Force empty line separator between import groups. boolean true sortImportsInGroupAlphabetically Force grouping alphabetically, in ASCII sort order. boolean false For example:
To configure the check so that it matches default Eclipse formatter configuration (tested on Kepler, Luna and Mars):
- group of static imports is on the top
- groups of non-static imports: "java" and "javax" packages first, then "org" and then all other imports
- imports will be sorted in the groups
- groups are separated by, at least, one blank line
<module name="CustomImportOrder"> <property name="customImportOrderRules" value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS"/> <property name="specialImportsRegExp" value="org"/> <property name="sortImportsInGroupAlphabetically" value="true"/> <property name="separateLineBetweenGroups" value="true"/> </module>To configure the check so that it matches default IntelliJ IDEA formatter configuration (tested on v14):
- group of static imports is on the bottom
- groups of non-static imports: all imports except of "javax" and "java", then "javax" and "java"
- imports will be sorted in the groups
- groups are separated by, at least, one blank line
Note: "separated" option is disabled because IDEA default has blank line between "java" and static imports, and no blank line between "javax" and "java"
<module name="CustomImportOrder"> <property name="customImportOrderRules" value="THIRD_PARTY_PACKAGE###SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE ###STATIC"/> <property name="specialImportsRegExp" value="^javax\."/> <property name="standardPackageRegExp" value="^java\."/> <property name="sortImportsInGroupAlphabetically" value="true"/> <property name="separateLineBetweenGroups" value="false"/> </module>To configure the check so that it matches default NetBeans formatter configuration (tested on v8):
- groups of non-static imports are not defined, all imports will be sorted as a one group
- static imports are not separated, they will be sorted along with other imports
<module name="CustomImportOrder"/>
To set RegExps for THIRD_PARTY_PACKAGE and STANDARD_JAVA_PACKAGE groups use thirdPartyPackageRegExp and standardPackageRegExp options.
<module name="CustomImportOrder"> <property name="customImportOrderRules" value="STATIC###SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/> <property name="thirdPartyPackageRegExp" value="com|org"/> <property name="standardPackageRegExp" value="^(java|javax)\."/> </module>Also, this check can be configured to force empty line separator between import groups. For example
<module name="CustomImportOrder"> <property name="separateLineBetweenGroups" value="true"/> </module>It is possible to enforce ASCII sort order of imports in groups using the following configuration:
<module name="CustomImportOrder"> <property name="sortImportsInGroupAlphabetically" value="true"/> </module>Example of ASCII order:
import java.awt.Dialog; import java.awt.Window; import java.awt.color.ColorSpace; import java.awt.Frame; // violation here - in ASCII order 'F' should go before 'c', // as all uppercase come before lowercase lettersTo force checking imports sequence such as:
configure as follows:package com.puppycrawl.tools.checkstyle.imports; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.Beta; import com.google.common.annotations.VisibleForTesting; import org.abego.treelayout.Configuration; import static sun.tools.util.ModifierFilter.ALL_ACCESS; import com.google.common.annotations.GwtCompatible; // violation here - should be in the // THIRD_PARTY_PACKAGE group import android.*;<module name="CustomImportOrder"> <property name="customImportOrderRules" value="SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STATIC###SPECIAL_IMPORTS"/> <property name="specialImportsRegExp" value="android.*"/> </module>
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private static classCustomImportOrderCheck.ImportDetailsContains import attributes as line number, import full path, import group.private static classCustomImportOrderCheck.RuleMatchForImportContains matching attributes assisting in definition of "best matching" group for import.
-
Field Summary
Fields Modifier and Type Field Description private java.util.List<java.lang.String>customImportOrderRulesList of order declaration customizing by user.private static java.util.regex.PatternGROUP_SEPARATOR_PATTERNPattern used to separate groups of imports.private java.util.List<CustomImportOrderCheck.ImportDetails>importToGroupListContains objects with import attributes.static java.lang.StringMSG_LEXA key is pointing to the warning message text in "messages.properties" file.static java.lang.StringMSG_LINE_SEPARATORA key is pointing to the warning message text in "messages.properties" file.static java.lang.StringMSG_NONGROUP_EXPECTEDA key is pointing to the warning message text in "messages.properties" file.static java.lang.StringMSG_NONGROUP_IMPORTA key is pointing to the warning message text in "messages.properties" file.static java.lang.StringMSG_ORDERA key is pointing to the warning message text in "messages.properties" file.private static java.lang.StringNON_GROUP_RULE_GROUPNON_GROUP group name.static java.lang.StringSAME_PACKAGE_RULE_GROUPSAME_PACKAGE group name.private java.lang.StringsamePackageDomainsRegExpRegExp for SAME_PACKAGE group imports.private intsamePackageMatchingDepthNumber of first domains for SAME_PACKAGE group.private booleanseparateLineBetweenGroupsForce empty line separator between import groups.private booleansortImportsInGroupAlphabeticallyForce grouping alphabetically, in ASCII order.static java.lang.StringSPECIAL_IMPORTS_RULE_GROUPSPECIAL_IMPORTS group name.private java.util.regex.PatternspecialImportsRegExpRegExp for SPECIAL_IMPORTS group imports.static java.lang.StringSTANDARD_JAVA_PACKAGE_RULE_GROUPSTANDARD_JAVA_PACKAGE group name.private java.util.regex.PatternstandardPackageRegExpRegExp for STANDARD_JAVA_PACKAGE group imports.static java.lang.StringSTATIC_RULE_GROUPSTATIC group name.static java.lang.StringTHIRD_PARTY_PACKAGE_RULE_GROUPTHIRD_PARTY_PACKAGE group name.private java.util.regex.PatternthirdPartyPackageRegExpRegExp for THIRD_PARTY_PACKAGE group imports.
-
Constructor Summary
Constructors Constructor Description CustomImportOrderCheck()
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description private voidaddRulesToList(java.lang.String ruleStr)Parses ordering rule and adds it to the list with rules.voidbeginTree(DetailAST rootAST)Called before the starting to process a tree.private static intcompareImports(java.lang.String import1, java.lang.String import2)Checks compare two import paths.private static java.lang.StringcreateSamePackageRegexp(int firstPackageDomainsCount, DetailAST packageNode)Creates samePackageDomainsRegExp of the first package domains.private static CustomImportOrderCheck.RuleMatchForImportfindBetterPatternMatch(java.lang.String importPath, java.lang.String group, java.util.regex.Pattern regExp, CustomImportOrderCheck.RuleMatchForImport currentBestMatch)Tries to find better matching regular expression: longer matching substring wins; in case of the same length, lower position of matching substring wins.private voidfinishImportList()Examine the order of all the imports and log any violations.voidfinishTree(DetailAST rootAST)Called after finished processing a tree.int[]getAcceptableTokens()The configurable token set.private intgetCountOfEmptyLinesBefore(int lineNo)Counts empty lines before given.int[]getDefaultTokens()Returns the default token a check is interested in.private static java.lang.StringgetFirstDomainsFromIdent(int firstPackageDomainsCount, java.lang.String packageFullPath)Extracts defined amount of domains from the left side of package/import identifier.private static java.lang.StringgetFullImportIdent(DetailAST token)Forms import full path.private java.lang.StringgetImportGroup(boolean isStatic, java.lang.String importPath)Get import valid group.private java.lang.StringgetNextImportGroup(int currentGroupNumber)Get next import group.int[]getRequiredTokens()The tokens that this check must be registered for.private booleanhasAnyImportInCurrentGroup(java.lang.String currentGroup)Checks if current group contains any import.private voidlogWrongImportGroupOrder(int currentImportLine, java.lang.String importGroup, java.lang.String currentGroupNumber, java.lang.String fullImportIdent)Log wrong import group order.voidsetCustomImportOrderRules(java.lang.String inputCustomImportOrder)Sets a custom import order from the rules in the string format specified by user.voidsetSeparateLineBetweenGroups(boolean value)Sets separateLineBetweenGroups specified by user.voidsetSortImportsInGroupAlphabetically(boolean value)Sets sortImportsInGroupAlphabetically specified by user.voidsetSpecialImportsRegExp(java.util.regex.Pattern regexp)Sets specialImportsRegExp specified by user.voidsetStandardPackageRegExp(java.util.regex.Pattern regexp)Sets standardRegExp specified by user.voidsetThirdPartyPackageRegExp(java.util.regex.Pattern regexp)Sets thirdPartyRegExp specified by user.voidvisitToken(DetailAST ast)Called to process a token.-
Methods inherited from class com.puppycrawl.tools.checkstyle.api.AbstractCheck
destroy, getClassLoader, getFileContents, getLine, getLines, getTabWidth, getTokenNames, init, isCommentNodesRequired, leaveToken, log, log, setClassLoader, setFileContents, setMessages, setTabWidth, setTokens
-
Methods inherited from class com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter
getCustomMessages, getId, getMessageBundle, getSeverity, getSeverityLevel, log, setId, setSeverity
-
Methods inherited from class com.puppycrawl.tools.checkstyle.api.AutomaticBean
configure, contextualize, finishLocalSetup, getConfiguration, setupChild
-
-
-
-
Field Detail
-
MSG_LINE_SEPARATOR
public static final java.lang.String MSG_LINE_SEPARATOR
A key is pointing to the warning message text in "messages.properties" file.- See Also:
- Constant Field Values
-
MSG_LEX
public static final java.lang.String MSG_LEX
A key is pointing to the warning message text in "messages.properties" file.- See Also:
- Constant Field Values
-
MSG_NONGROUP_IMPORT
public static final java.lang.String MSG_NONGROUP_IMPORT
A key is pointing to the warning message text in "messages.properties" file.- See Also:
- Constant Field Values
-
MSG_NONGROUP_EXPECTED
public static final java.lang.String MSG_NONGROUP_EXPECTED
A key is pointing to the warning message text in "messages.properties" file.- See Also:
- Constant Field Values
-
MSG_ORDER
public static final java.lang.String MSG_ORDER
A key is pointing to the warning message text in "messages.properties" file.- See Also:
- Constant Field Values
-
STATIC_RULE_GROUP
public static final java.lang.String STATIC_RULE_GROUP
STATIC group name.- See Also:
- Constant Field Values
-
SAME_PACKAGE_RULE_GROUP
public static final java.lang.String SAME_PACKAGE_RULE_GROUP
SAME_PACKAGE group name.- See Also:
- Constant Field Values
-
THIRD_PARTY_PACKAGE_RULE_GROUP
public static final java.lang.String THIRD_PARTY_PACKAGE_RULE_GROUP
THIRD_PARTY_PACKAGE group name.- See Also:
- Constant Field Values
-
STANDARD_JAVA_PACKAGE_RULE_GROUP
public static final java.lang.String STANDARD_JAVA_PACKAGE_RULE_GROUP
STANDARD_JAVA_PACKAGE group name.- See Also:
- Constant Field Values
-
SPECIAL_IMPORTS_RULE_GROUP
public static final java.lang.String SPECIAL_IMPORTS_RULE_GROUP
SPECIAL_IMPORTS group name.- See Also:
- Constant Field Values
-
NON_GROUP_RULE_GROUP
private static final java.lang.String NON_GROUP_RULE_GROUP
NON_GROUP group name.- See Also:
- Constant Field Values
-
GROUP_SEPARATOR_PATTERN
private static final java.util.regex.Pattern GROUP_SEPARATOR_PATTERN
Pattern used to separate groups of imports.
-
customImportOrderRules
private final java.util.List<java.lang.String> customImportOrderRules
List of order declaration customizing by user.
-
importToGroupList
private final java.util.List<CustomImportOrderCheck.ImportDetails> importToGroupList
Contains objects with import attributes.
-
samePackageDomainsRegExp
private java.lang.String samePackageDomainsRegExp
RegExp for SAME_PACKAGE group imports.
-
standardPackageRegExp
private java.util.regex.Pattern standardPackageRegExp
RegExp for STANDARD_JAVA_PACKAGE group imports.
-
thirdPartyPackageRegExp
private java.util.regex.Pattern thirdPartyPackageRegExp
RegExp for THIRD_PARTY_PACKAGE group imports.
-
specialImportsRegExp
private java.util.regex.Pattern specialImportsRegExp
RegExp for SPECIAL_IMPORTS group imports.
-
separateLineBetweenGroups
private boolean separateLineBetweenGroups
Force empty line separator between import groups.
-
sortImportsInGroupAlphabetically
private boolean sortImportsInGroupAlphabetically
Force grouping alphabetically, in ASCII order.
-
samePackageMatchingDepth
private int samePackageMatchingDepth
Number of first domains for SAME_PACKAGE group.
-
-
Method Detail
-
setStandardPackageRegExp
public final void setStandardPackageRegExp(java.util.regex.Pattern regexp)
Sets standardRegExp specified by user.- Parameters:
regexp- user value.
-
setThirdPartyPackageRegExp
public final void setThirdPartyPackageRegExp(java.util.regex.Pattern regexp)
Sets thirdPartyRegExp specified by user.- Parameters:
regexp- user value.
-
setSpecialImportsRegExp
public final void setSpecialImportsRegExp(java.util.regex.Pattern regexp)
Sets specialImportsRegExp specified by user.- Parameters:
regexp- user value.
-
setSeparateLineBetweenGroups
public final void setSeparateLineBetweenGroups(boolean value)
Sets separateLineBetweenGroups specified by user.- Parameters:
value- user value.
-
setSortImportsInGroupAlphabetically
public final void setSortImportsInGroupAlphabetically(boolean value)
Sets sortImportsInGroupAlphabetically specified by user.- Parameters:
value- user value.
-
setCustomImportOrderRules
public final void setCustomImportOrderRules(java.lang.String inputCustomImportOrder)
Sets a custom import order from the rules in the string format specified by user.- Parameters:
inputCustomImportOrder- user value.
-
getDefaultTokens
public int[] getDefaultTokens()
Description copied from class:AbstractCheckReturns the default token a check is interested in. Only used if the configuration for a check does not define the tokens.- Specified by:
getDefaultTokensin classAbstractCheck- Returns:
- the default tokens
- See Also:
TokenTypes
-
getAcceptableTokens
public int[] getAcceptableTokens()
Description copied from class:AbstractCheckThe configurable token set. Used to protect Checks against malicious users who specify an unacceptable token set in the configuration file. The default implementation returns the check's default tokens.- Specified by:
getAcceptableTokensin classAbstractCheck- Returns:
- the token set this check is designed for.
- See Also:
TokenTypes
-
getRequiredTokens
public int[] getRequiredTokens()
Description copied from class:AbstractCheckThe tokens that this check must be registered for.- Specified by:
getRequiredTokensin classAbstractCheck- Returns:
- the token set this must be registered for.
- See Also:
TokenTypes
-
beginTree
public void beginTree(DetailAST rootAST)
Description copied from class:AbstractCheckCalled before the starting to process a tree. Ideal place to initialize information that is to be collected whilst processing a tree.- Overrides:
beginTreein classAbstractCheck- Parameters:
rootAST- the root of the tree
-
visitToken
public void visitToken(DetailAST ast)
Description copied from class:AbstractCheckCalled to process a token.- Overrides:
visitTokenin classAbstractCheck- Parameters:
ast- the token to process
-
finishTree
public void finishTree(DetailAST rootAST)
Description copied from class:AbstractCheckCalled after finished processing a tree. Ideal place to report on information collected whilst processing a tree.- Overrides:
finishTreein classAbstractCheck- Parameters:
rootAST- the root of the tree
-
finishImportList
private void finishImportList()
Examine the order of all the imports and log any violations.
-
logWrongImportGroupOrder
private void logWrongImportGroupOrder(int currentImportLine, java.lang.String importGroup, java.lang.String currentGroupNumber, java.lang.String fullImportIdent)Log wrong import group order.- Parameters:
currentImportLine- line number of current import current import.importGroup- import group.currentGroupNumber- current group number we are checking.fullImportIdent- full import name.
-
getNextImportGroup
private java.lang.String getNextImportGroup(int currentGroupNumber)
Get next import group.- Parameters:
currentGroupNumber- current group number.- Returns:
- next import group.
-
hasAnyImportInCurrentGroup
private boolean hasAnyImportInCurrentGroup(java.lang.String currentGroup)
Checks if current group contains any import.- Parameters:
currentGroup- current group.- Returns:
- true, if current group contains at least one import.
-
getImportGroup
private java.lang.String getImportGroup(boolean isStatic, java.lang.String importPath)Get import valid group.- Parameters:
isStatic- is static import.importPath- full import path.- Returns:
- import valid group.
-
findBetterPatternMatch
private static CustomImportOrderCheck.RuleMatchForImport findBetterPatternMatch(java.lang.String importPath, java.lang.String group, java.util.regex.Pattern regExp, CustomImportOrderCheck.RuleMatchForImport currentBestMatch)
Tries to find better matching regular expression: longer matching substring wins; in case of the same length, lower position of matching substring wins.- Parameters:
importPath- Full import identifiergroup- Import group we are trying to assign the importregExp- Regular expression for import groupcurrentBestMatch- object with currently best match- Returns:
- better match (if found) or the same (currentBestMatch)
-
compareImports
private static int compareImports(java.lang.String import1, java.lang.String import2)Checks compare two import paths.- Parameters:
import1- current import.import2- previous import.- Returns:
- a negative integer, zero, or a positive integer as the specified String is greater than, equal to, or less than this String, ignoring case considerations.
-
getCountOfEmptyLinesBefore
private int getCountOfEmptyLinesBefore(int lineNo)
Counts empty lines before given.- Parameters:
lineNo- Line number of current import.- Returns:
- count of empty lines before given.
-
getFullImportIdent
private static java.lang.String getFullImportIdent(DetailAST token)
Forms import full path.- Parameters:
token- current token.- Returns:
- full path or null.
-
addRulesToList
private void addRulesToList(java.lang.String ruleStr)
Parses ordering rule and adds it to the list with rules.- Parameters:
ruleStr- String with rule.
-
createSamePackageRegexp
private static java.lang.String createSamePackageRegexp(int firstPackageDomainsCount, DetailAST packageNode)Creates samePackageDomainsRegExp of the first package domains.- Parameters:
firstPackageDomainsCount- number of first package domains.packageNode- package node.- Returns:
- same package regexp.
-
getFirstDomainsFromIdent
private static java.lang.String getFirstDomainsFromIdent(int firstPackageDomainsCount, java.lang.String packageFullPath)Extracts defined amount of domains from the left side of package/import identifier.- Parameters:
firstPackageDomainsCount- number of first package domains.packageFullPath- full identifier containing path to package or imported object.- Returns:
- String with defined amount of domains or full identifier (if full identifier had less domain then specified)
-
-