001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2017 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018//////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle.utils; 021 022import java.io.IOException; 023import java.lang.reflect.Constructor; 024import java.lang.reflect.Modifier; 025import java.util.Collection; 026import java.util.Set; 027import java.util.stream.Collectors; 028 029import com.google.common.reflect.ClassPath; 030import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; 031import com.puppycrawl.tools.checkstyle.api.AbstractCheck; 032import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; 033import com.puppycrawl.tools.checkstyle.api.AuditListener; 034import com.puppycrawl.tools.checkstyle.api.AutomaticBean; 035import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilter; 036import com.puppycrawl.tools.checkstyle.api.Filter; 037import com.puppycrawl.tools.checkstyle.api.RootModule; 038 039/** 040 * Contains utility methods for module reflection. 041 * @author LuoLiangchen 042 */ 043public final class ModuleReflectionUtils { 044 045 /** Prevent instantiation. */ 046 private ModuleReflectionUtils() { 047 } 048 049 /** 050 * Gets checkstyle's modules (directly, not recursively) in the given packages. 051 * @param packages the collection of package names to use 052 * @param loader the class loader used to load Checkstyle package names 053 * @return the set of checkstyle's module classes 054 * @throws IOException if the attempt to read class path resources failed 055 * @see #isCheckstyleModule(Class) 056 */ 057 public static Set<Class<?>> getCheckstyleModules( 058 Collection<String> packages, ClassLoader loader) throws IOException { 059 final ClassPath classPath = ClassPath.from(loader); 060 return packages.stream() 061 .flatMap(pkg -> classPath.getTopLevelClasses(pkg).stream()) 062 .map(ClassPath.ClassInfo::load) 063 .filter(ModuleReflectionUtils::isCheckstyleModule) 064 .collect(Collectors.toSet()); 065 } 066 067 /** 068 * Checks whether a class may be considered as a checkstyle module. Checkstyle's modules are 069 * non-abstract classes, which are either checkstyle's checks, file sets, filters, file filters, 070 * {@code TreeWalker} filters, audit listener, or root module. 071 * @param clazz class to check. 072 * @return true if the class may be considered as the checkstyle module. 073 */ 074 public static boolean isCheckstyleModule(Class<?> clazz) { 075 return isValidCheckstyleClass(clazz) 076 && (isCheckstyleCheck(clazz) 077 || isFileSetModule(clazz) 078 || isFilterModule(clazz) 079 || isFileFilterModule(clazz) 080 || isTreeWalkerFilterModule(clazz) 081 || isAuditListener(clazz) 082 || isRootModule(clazz)); 083 } 084 085 /** 086 * Checks whether a class extends 'AutomaticBean', is non-abstract, and has a default 087 * constructor. 088 * @param clazz class to check. 089 * @return true if a class may be considered a valid production class. 090 */ 091 public static boolean isValidCheckstyleClass(Class<?> clazz) { 092 return AutomaticBean.class.isAssignableFrom(clazz) 093 && !Modifier.isAbstract(clazz.getModifiers()) 094 && hasDefaultConstructor(clazz); 095 } 096 097 /** 098 * Checks if the class has a default constructor. 099 * @param clazz class to check 100 * @return true if the class has a default constructor. 101 */ 102 private static boolean hasDefaultConstructor(Class<?> clazz) { 103 boolean result = false; 104 for (Constructor<?> constructor : clazz.getDeclaredConstructors()) { 105 if (constructor.getParameterCount() == 0) { 106 result = true; 107 break; 108 } 109 } 110 return result; 111 } 112 113 /** 114 * Checks whether a class may be considered as the checkstyle check. 115 * Checkstyle's checks are classes which implement 'AbstractCheck' interface. 116 * @param clazz class to check. 117 * @return true if a class may be considered as the checkstyle check. 118 */ 119 public static boolean isCheckstyleCheck(Class<?> clazz) { 120 return AbstractCheck.class.isAssignableFrom(clazz); 121 } 122 123 /** 124 * Checks whether a class may be considered as the checkstyle file set. 125 * Checkstyle's file sets are classes which implement 'AbstractFileSetCheck' interface. 126 * @param clazz class to check. 127 * @return true if a class may be considered as the checkstyle file set. 128 */ 129 public static boolean isFileSetModule(Class<?> clazz) { 130 return AbstractFileSetCheck.class.isAssignableFrom(clazz); 131 } 132 133 /** 134 * Checks whether a class may be considered as the checkstyle filter. 135 * Checkstyle's filters are classes which implement 'Filter' interface. 136 * @param clazz class to check. 137 * @return true if a class may be considered as the checkstyle filter. 138 */ 139 public static boolean isFilterModule(Class<?> clazz) { 140 return Filter.class.isAssignableFrom(clazz); 141 } 142 143 /** 144 * Checks whether a class may be considered as the checkstyle file filter. 145 * Checkstyle's file filters are classes which implement 'BeforeExecutionFileFilter' interface. 146 * @param clazz class to check. 147 * @return true if a class may be considered as the checkstyle file filter. 148 */ 149 public static boolean isFileFilterModule(Class<?> clazz) { 150 return BeforeExecutionFileFilter.class.isAssignableFrom(clazz); 151 } 152 153 /** 154 * Checks whether a class may be considered as the checkstyle audit listener module. 155 * Checkstyle's audit listener modules are classes which implement 'AuditListener' interface. 156 * @param clazz class to check. 157 * @return true if a class may be considered as the checkstyle audit listener module. 158 */ 159 public static boolean isAuditListener(Class<?> clazz) { 160 return AuditListener.class.isAssignableFrom(clazz); 161 } 162 163 /** 164 * Checks whether a class may be considered as the checkstyle root module. 165 * Checkstyle's root modules are classes which implement 'RootModule' interface. 166 * @param clazz class to check. 167 * @return true if a class may be considered as the checkstyle root module. 168 */ 169 public static boolean isRootModule(Class<?> clazz) { 170 return RootModule.class.isAssignableFrom(clazz); 171 } 172 173 /** 174 * Checks whether a class may be considered as the checkstyle {@code TreeWalker} filter. 175 * Checkstyle's {@code TreeWalker} filters are classes which implement 'TreeWalkerFilter' 176 * interface. 177 * @param clazz class to check. 178 * @return true if a class may be considered as the checkstyle {@code TreeWalker} filter. 179 */ 180 public static boolean isTreeWalkerFilterModule(Class<?> clazz) { 181 return TreeWalkerFilter.class.isAssignableFrom(clazz); 182 } 183}