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.

Notes: Rules are configured as a comma-separated ordered list.

Note: '###' group separator is deprecated (in favor of a comma-separated list), but is currently supported for backward compatibility.

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.

Since:
5.8
  • Field Details

    • MSG_LINE_SEPARATOR

      public static final String MSG_LINE_SEPARATOR
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • MSG_SEPARATED_IN_GROUP

      public static final String MSG_SEPARATED_IN_GROUP
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • MSG_LEX

      public static final String MSG_LEX
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • MSG_NONGROUP_IMPORT

      public static final String MSG_NONGROUP_IMPORT
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • MSG_NONGROUP_EXPECTED

      public static final String MSG_NONGROUP_EXPECTED
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • MSG_ORDER

      public static final String MSG_ORDER
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • STATIC_RULE_GROUP

      public static final String STATIC_RULE_GROUP
      STATIC group name.
      See Also:
    • SAME_PACKAGE_RULE_GROUP

      public static final String SAME_PACKAGE_RULE_GROUP
      SAME_PACKAGE group name.
      See Also:
    • THIRD_PARTY_PACKAGE_RULE_GROUP

      public static final String THIRD_PARTY_PACKAGE_RULE_GROUP
      THIRD_PARTY_PACKAGE group name.
      See Also:
    • STANDARD_JAVA_PACKAGE_RULE_GROUP

      public static final String STANDARD_JAVA_PACKAGE_RULE_GROUP
      STANDARD_JAVA_PACKAGE group name.
      See Also:
    • SPECIAL_IMPORTS_RULE_GROUP

      public static final String SPECIAL_IMPORTS_RULE_GROUP
      SPECIAL_IMPORTS group name.
      See Also:
    • NON_GROUP_RULE_GROUP

      private static final String NON_GROUP_RULE_GROUP
      NON_GROUP group name.
      See Also:
    • GROUP_SEPARATOR_PATTERN

      private static final Pattern GROUP_SEPARATOR_PATTERN
      Pattern used to separate groups of imports.
    • customImportOrderRules

      private final List<String> customImportOrderRules
      Specify ordered list of import groups.
    • importToGroupList

      private final List<CustomImportOrderCheck.ImportDetails> importToGroupList
      Contains objects with import attributes.
    • samePackageDomainsRegExp

      private String samePackageDomainsRegExp
      Specify RegExp for SAME_PACKAGE group imports.
    • standardPackageRegExp

      private Pattern standardPackageRegExp
      Specify RegExp for STANDARD_JAVA_PACKAGE group imports.
    • thirdPartyPackageRegExp

      private Pattern thirdPartyPackageRegExp
      Specify RegExp for THIRD_PARTY_PACKAGE group imports.
    • specialImportsRegExp

      private Pattern specialImportsRegExp
      Specify 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 sort order.
    • samePackageMatchingDepth

      private int samePackageMatchingDepth
      Number of first domains for SAME_PACKAGE group.
  • Constructor Details

    • CustomImportOrderCheck

      public CustomImportOrderCheck()
  • Method Details

    • setStandardPackageRegExp

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

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

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

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

      public final void setSortImportsInGroupAlphabetically(boolean value)
      Setter to force grouping alphabetically, in ASCII sort order.
      Parameters:
      value - user value.
      Since:
      5.8
    • setCustomImportOrderRules

      public final void setCustomImportOrderRules(String... rules)
      Setter to specify ordered list of import groups.
      Parameters:
      rules - user value.
      Since:
      5.8
    • getDefaultTokens

      public int[] getDefaultTokens()
      Description copied from class: AbstractCheck
      Returns the default token a check is interested in. Only used if the configuration for a check does not define the tokens.
      Specified by:
      getDefaultTokens in class AbstractCheck
      Returns:
      the default tokens
      See Also:
    • 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:
    • getRequiredTokens

      public int[] getRequiredTokens()
      Description copied from class: AbstractCheck
      The tokens that this check must be registered for.
      Specified by:
      getRequiredTokens in class AbstractCheck
      Returns:
      the token set this must be registered for.
      See Also:
    • 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
    • visitToken

      public void visitToken(DetailAST ast)
      Description copied from class: AbstractCheck
      Called to process a token.
      Overrides:
      visitToken in class AbstractCheck
      Parameters:
      ast - the token to process
    • 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.
    • validateMissedEmptyLine

      private void validateMissedEmptyLine(CustomImportOrderCheck.ImportDetails previousImport, CustomImportOrderCheck.ImportDetails importObject, String fullImportIdent)
      Log violation if empty line is missed.
      Parameters:
      previousImport - previous import from current group.
      importObject - current import.
      fullImportIdent - full import identifier.
    • validateExtraEmptyLine

      private void validateExtraEmptyLine(CustomImportOrderCheck.ImportDetails previousImport, CustomImportOrderCheck.ImportDetails importObject, String fullImportIdent)
      Log violation if extra empty line is present.
      Parameters:
      previousImport - previous import from current group.
      importObject - current import.
      fullImportIdent - full import identifier.
    • getFirstGroup

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

      private boolean isAlphabeticalOrderBroken(String previousImport, 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.
    • isEmptyLineMissed

      private boolean isEmptyLineMissed(CustomImportOrderCheck.ImportDetails previousImportObject, CustomImportOrderCheck.ImportDetails currentImportObject)
      Examine empty lines between groups.
      Parameters:
      previousImportObject - previous import in current group.
      currentImportObject - current import.
      Returns:
      true, if current import NOT separated from previous import by empty line.
    • isSeparatedByExtraEmptyLine

      private boolean isSeparatedByExtraEmptyLine(CustomImportOrderCheck.ImportDetails previousImportObject, CustomImportOrderCheck.ImportDetails currentImportObject)
      Examine that imports separated by more than one empty line.
      Parameters:
      previousImportObject - previous import in current group.
      currentImportObject - current import.
      Returns:
      true, if current import separated from previous by more than one empty line.
    • logWrongImportGroupOrder

      private void logWrongImportGroupOrder(DetailAST importAST, String importGroup, String currentGroupNumber, 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 String getNextImportGroup(int currentGroupNumber)
      Get next import group.
      Parameters:
      currentGroupNumber - current group number.
      Returns:
      next import group.
    • hasAnyImportInCurrentGroup

      private boolean hasAnyImportInCurrentGroup(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 String getImportGroup(boolean isStatic, 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(String importPath, String group, 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(String import1, 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 String getFullImportIdent(DetailAST token)
      Forms import full path.
      Parameters:
      token - current token.
      Returns:
      full path or null.
    • addRulesToList

      private void addRulesToList(String ruleStr)
      Parses ordering rule and adds it to the list with rules.
      Parameters:
      ruleStr - String with rule.
      Throws:
      IllegalArgumentException - when SAME_PACKAGE rule parameter is not positive integer
      IllegalStateException - when ruleStr is unexpected value
    • createSamePackageRegexp

      private static 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 String getFirstDomainsFromIdent(int firstPackageDomainsCount, 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)