//////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. // Copyright (C) 2001-2017 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //////////////////////////////////////////////////////////////////////////////// package com.puppycrawl.tools.checkstyle.checks.imports; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * <p> * Checks for imports from a set of illegal packages. * By default, the check rejects all {@code sun.*} packages * since programs that contain direct calls to the {@code sun.*} packages * are <a href="http://www.oracle.com/technetwork/java/faq-sun-packages-142232.html"> * not 100% Pure Java</a>. * </p> * <p> * To reject other packages, set property illegalPkgs to a comma-separated * list of the illegal packages. * </p> * <p> * An example of how to configure the check is: * </p> * <pre> * <module name="IllegalImport"/> * </pre> * <p> * An example of how to configure the check so that it rejects packages * {@code java.io.*} and {@code java.sql.*} is * </p> * <pre> * <module name="IllegalImport"> * <property name="illegalPkgs" value="java.io, java.sql"/> * </module> * * Compatible with Java 1.5 source. * * </pre> * @author Oliver Burn * @author Lars Kühne */ public class IllegalImportCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" * file. */ public static final String MSG_KEY = "import.illegal"; /** The compiled regular expressions for packages. */ private final List<Pattern> illegalPkgsRegexps = new ArrayList<>(); /** The compiled regular expressions for classes. */ private final List<Pattern> illegalClassesRegexps = new ArrayList<>(); /** List of illegal packages. */ private String[] illegalPkgs; /** List of illegal classes. */ private String[] illegalClasses; /** * Whether the packages or class names * should be interpreted as regular expressions. */ private boolean regexp; /** * Creates a new {@code IllegalImportCheck} instance. */ public IllegalImportCheck() { setIllegalPkgs("sun"); } /** * Set the list of illegal packages. * @param from array of illegal packages */ public final void setIllegalPkgs(String... from) { illegalPkgs = from.clone(); illegalPkgsRegexps.clear(); for (String illegalPkg : illegalPkgs) { illegalPkgsRegexps.add(CommonUtils.createPattern("^" + illegalPkg + "\\..*")); } } /** * Set the list of illegal classes. * @param from array of illegal classes */ public void setIllegalClasses(String... from) { illegalClasses = from.clone(); illegalClassesRegexps.clear(); for (String illegalClass : illegalClasses) { illegalClassesRegexps.add(CommonUtils.createPattern(illegalClass)); } } /** * Controls whether the packages or class names * should be interpreted as regular expressions. * @param regexp a {@code Boolean} value */ public void setRegexp(boolean regexp) { this.regexp = regexp; } @Override public int[] getDefaultTokens() { return getAcceptableTokens(); } @Override public int[] getAcceptableTokens() { return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; } @Override public int[] getRequiredTokens() { return getAcceptableTokens(); } @Override public void visitToken(DetailAST ast) { final FullIdent imp; if (ast.getType() == TokenTypes.IMPORT) { imp = FullIdent.createFullIdentBelow(ast); } else { imp = FullIdent.createFullIdent( ast.getFirstChild().getNextSibling()); } if (isIllegalImport(imp.getText())) { log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY, imp.getText()); } } /** * Checks if an import matches one of the regular expressions * for illegal packages or illegal class names. * @param importText the argument of the import keyword * @return if {@code importText} matches one of the regular expressions * for illegal packages or illegal class names */ private boolean isIllegalImportByRegularExpressions(String importText) { boolean result = false; for (Pattern pattern : illegalPkgsRegexps) { if (pattern.matcher(importText).matches()) { result = true; break; } } if (!result) { for (Pattern pattern : illegalClassesRegexps) { if (pattern.matcher(importText).matches()) { result = true; break; } } } return result; } /** * Checks if an import is from a package or class name that must not be used. * @param importText the argument of the import keyword * @return if {@code importText} contains an illegal package prefix or equals illegal class name */ private boolean isIllegalImportByPackagesAndClassNames(String importText) { boolean result = false; for (String element : illegalPkgs) { if (importText.startsWith(element + ".")) { result = true; break; } } if (!result && illegalClasses != null) { for (String element : illegalClasses) { if (importText.equals(element)) { result = true; break; } } } return result; } /** * Checks if an import is from a package or class name that must not be used. * @param importText the argument of the import keyword * @return if {@code importText} is illegal import */ private boolean isIllegalImport(String importText) { final boolean result; if (regexp) { result = isIllegalImportByRegularExpressions(importText); } else { result = isIllegalImportByPackagesAndClassNames(importText); } return result; } }