Class 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; //#8
       
      If 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 contain some imports that have particular meaning for the user.

    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:

    1. STATIC has top priority
    2. SAME_PACKAGE has second priority
    3. 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.
    4. 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 than "Check" position.

    • Property customImportOrderRules - Specify format of order declaration customizing by user. Type is java.lang.String. Default value is "".
    • Property standardPackageRegExp - Specify RegExp for STANDARD_JAVA_PACKAGE group imports. Type is java.util.regex.Pattern. Default value is "^(java|javax)\.".
    • Property thirdPartyPackageRegExp - Specify RegExp for THIRD_PARTY_PACKAGE group imports. Type is java.util.regex.Pattern. Default value is ".*".
    • Property specialImportsRegExp - Specify RegExp for SPECIAL_IMPORTS group imports. Type is java.util.regex.Pattern. Default value is "^$".
    • Property separateLineBetweenGroups - Force empty line separator between import groups. Type is boolean. Default value is true.
    • Property sortImportsInGroupAlphabetically - Force grouping alphabetically, in ASCII sort order. Type is boolean. Default value is false.

    To configure the check :

     <module name="CustomImportOrder"/>
     

    Example:

     package com.company;
     import org.apache.commons.io.FileUtils; // OK
     import static java.util.*; // OK
     import java.time.*; // OK
     import static java.io.*; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check so that it checks in the order (static imports,standard java packages,third party package):

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE"/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
    
     import java.time.*; // OK
     import javax.net.*; // OK
     import static java.io.*; // violation as static imports should be in top
    
     import org.apache.commons.io.FileUtils; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check such that only java packages are included in standard java packages

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###THIRD_PARTY_PACKAGE"/>
       <property name="standardPackageRegExp" value="^java\."/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // OK
    
     import java.time.*; // OK
     import javax.net.*; // violation as it is not included in standard java package group.
    
     import org.apache.commons.io.FileUtils; // violation
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check to include only "com" packages as third party group imports:

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE"/>
       <property name="thirdPartyPackageRegExp" value="^com\."/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // OK
    
     import java.time.*; // OK
     import javax.net.*; // OK
    
     import org.apache.commons.io.FileUtils; // violation(should be in end)
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // violation
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check to force some packages in special import group:

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###SPECIAL_IMPORTS###STANDARD_JAVA_PACKAGE"/>
       <property name="specialImportsRegExp" value="^org\."/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // OK
    
     import org.json.JSONObject; // OK
    
     import java.time.*; // OK
     import javax.net.*; // OK
    
     import org.apache.commons.io.FileUtils; // violation
     

    To configure the check such that empty line separator between two groups is enabled:

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE"/>
       <property name="specialImportsRegExp" value="^org\."/>
       <property name="thirdPartyPackageRegExp" value="^com\."/>
       <property name="separateLineBetweenGroups" value="true"/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // OK
    
     import java.time.*; // OK
     import javax.net.*; // OK
     import org.apache.commons.io.FileUtils; // violation
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // violation
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check such that import groups are forced to be sorted alphabetically:

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE"/>
       <property name="specialImportsRegExp" value="^org\."/>
       <property name="thirdPartyPackageRegExp" value="^com\."/>
       <property name="separateLineBetweenGroups" value="false"/>
       <property name="sortImportsInGroupAlphabetically" value="true"/>
     </module>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // Violation since it should come before"java.util"
    
     import java.time.*; // OK
     import javax.net.*; // OK
     import org.apache.commons.io.FileUtils; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check so that it matches default Eclipse formatter configuration (tested on Kepler and Luna releases):

    • 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 single blank line

    Notes:

    • "com" package is not mentioned on configuration, because it is ignored by Eclipse Kepler and Luna (looks like Eclipse defect)
    • configuration below doesn't work in all 100% cases due to inconsistent behavior prior to Mars release, but covers most scenarios
     <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>
     

    Example:

     package com.company;
    
     import static java.util.*; // OK
     import static java.io.*; // Violation since it should come before"java.util"
    
     import java.time.*; // OK
     import javax.net.*; // OK
     import org.apache.commons.io.FileUtils; // Violation should be separated by space
    
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     

    To configure the check so that it matches default Eclipse formatter configuration (tested on Mars release):

    • group of static imports is on the top
    • groups of non-static imports: "java" and "javax" packages first, then "org" and "com", then all other imports as one group
    • imports will be sorted in the groups
    • groups are separated by one blank line
     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE"/>
       <property name="specialImportsRegExp" value="^org\."/>
       <property name="thirdPartyPackageRegExp" value="^com\."/>
       <property name="sortImportsInGroupAlphabetically" value="true"/>
       <property name="separateLineBetweenGroups" value="true"/>
     </module>
     

    Example:

     package com.company;
    
     import static java.io.*; // OK
     import static java.util.*; // OK
    
     import java.time.*; // OK
     import javax.net.*; // OK
    
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // Violation
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // Violation
    
     import org.apache.commons.io.FileUtils;
     

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

    Example:

     package com.company;
    
     import static java.io.*; // OK
     import static java.util.*; // OK
    
     import java.time.*; // violation should be in standard package group
                        // below special import
    
     import javax.net.*; // Violation should be in special import group
    
     import org.apache.commons.io.FileUtils; // Violation should be in
                                            // THIRD PARTY PACKAGE GROUP
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // Violation
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // Violation
     

    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"/>
     

    Example:

     package com.company;
    
     import static java.io.*; // OK
     import static java.util.*; // OK
     import java.time.*; // OK
     import javax.net.*; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
    
     import org.apache.commons.io.FileUtils; // should not be separated by line
     

    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>
     

    Example:

     package com.company;
    
     import static java.io.*; // OK
     import static java.util.*; // OK
     import java.time.*; // violation
     import javax.net.*; // violation
    
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     import org.apache.commons.io.FileUtils; // OK
     

    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>
     

    Example:

     package com.company;
    
     import static java.io.*; // OK
     import static java.util.*; // OK
     import java.time.*; // OK
     import javax.net.*; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; // OK
     import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck; // OK
     import org.apache.commons.io.FileUtils; // OK
     

    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 letters
     

    To force checking imports sequence such as:

     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.*;
     

    configure as follows:

     <module name="CustomImportOrder">
       <property name="customImportOrderRules"
         value="SAME_PACKAGE(3)###THIRD_PARTY_PACKAGE###STATIC###SPECIAL_IMPORTS"/>
       <property name="specialImportsRegExp" value="^android\."/>
     </module>
     

    Parent is com.puppycrawl.tools.checkstyle.TreeWalker

    Violation Message Keys:

    • custom.import.order
    • custom.import.order.lex
    • custom.import.order.line.separator
    • custom.import.order.nonGroup.expected
    • custom.import.order.nonGroup.import
    • custom.import.order.separated.internally
    Since:
    5.8
    • Method Detail

      • setStandardPackageRegExp

        public final void setStandardPackageRegExp​(java.util.regex.Pattern regexp)
        Setter to specify RegExp for STANDARD_JAVA_PACKAGE group imports.
        Parameters:
        regexp - user value.
      • setThirdPartyPackageRegExp

        public final void setThirdPartyPackageRegExp​(java.util.regex.Pattern regexp)
        Setter to specify RegExp for THIRD_PARTY_PACKAGE group imports.
        Parameters:
        regexp - user value.
      • setSpecialImportsRegExp

        public final void setSpecialImportsRegExp​(java.util.regex.Pattern regexp)
        Setter to specify RegExp for SPECIAL_IMPORTS group imports.
        Parameters:
        regexp - user value.
      • setSeparateLineBetweenGroups

        public final void setSeparateLineBetweenGroups​(boolean value)
        Setter to force empty line separator between import groups.
        Parameters:
        value - user value.
      • setCustomImportOrderRules

        public final void setCustomImportOrderRules​(java.lang.String inputCustomImportOrder)
        Setter to specify format of order declaration customizing by user.
        Parameters:
        inputCustomImportOrder - user value.
      • getAcceptableTokens

        public int[] getAcceptableTokens()
        Description copied from class: AbstractCheck
        The 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:
        getAcceptableTokens in class AbstractCheck
        Returns:
        the token set this check is designed for.
        See Also:
        TokenTypes
      • beginTree

        public void beginTree​(DetailAST rootAST)
        Description copied from class: AbstractCheck
        Called before the starting to process a tree. Ideal place to initialize information that is to be collected whilst processing a tree.
        Overrides:
        beginTree in class AbstractCheck
        Parameters:
        rootAST - the root of the tree
      • finishTree

        public void finishTree​(DetailAST rootAST)
        Description copied from class: AbstractCheck
        Called after finished processing a tree. Ideal place to report on information collected whilst processing a tree.
        Overrides:
        finishTree in class AbstractCheck
        Parameters:
        rootAST - the root of the tree
      • finishImportList

        private void finishImportList()
        Examine the order of all the imports and log any violations.
      • getFirstGroup

        private java.lang.String getFirstGroup()
        Get first import group.
        Returns:
        first import group of file.
      • isAlphabeticalOrderBroken

        private boolean isAlphabeticalOrderBroken​(java.lang.String previousImport,
                                                  java.lang.String currentImport)
        Examine alphabetical order of imports.
        Parameters:
        previousImport - previous import of current group.
        currentImport - current import.
        Returns:
        true, if previous and current import are not in alphabetical order.
      • logWrongImportGroupOrder

        private void logWrongImportGroupOrder​(DetailAST importAST,
                                              java.lang.String importGroup,
                                              java.lang.String currentGroupNumber,
                                              java.lang.String fullImportIdent)
        Log wrong import group order.
        Parameters:
        importAST - import ast.
        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 identifier
        group - Import group we are trying to assign the import
        regExp - Regular expression for import group
        currentBestMatch - 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.
      • getCountOfEmptyLinesBetween

        private int getCountOfEmptyLinesBetween​(int fromLineNo,
                                                int toLineNo)
        Counts empty lines between given parameters.
        Parameters:
        fromLineNo - One-based line number of previous import.
        toLineNo - One-based line number of current import.
        Returns:
        count of empty lines between given parameters, exclusive, eg., (fromLineNo, toLineNo).
      • 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.
        Throws:
        java.lang.IllegalArgumentException - when SAME_PACKAGE rule parameter is not positive integer
        java.lang.IllegalStateException - when ruleStr is unexpected value
      • 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 than specified)