001//////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code for adherence to a set of rules. 003// Copyright (C) 2001-2018 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 && (isCheckstyleTreeWalkerCheck(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 * which has TreeWalker as a parent. 116 * Checkstyle's checks are classes which implement 'AbstractCheck' interface. 117 * @param clazz class to check. 118 * @return true if a class may be considered as the checkstyle check. 119 */ 120 public static boolean isCheckstyleTreeWalkerCheck(Class<?> clazz) { 121 return AbstractCheck.class.isAssignableFrom(clazz); 122 } 123 124 /** 125 * Checks whether a class may be considered as the checkstyle file set. 126 * Checkstyle's file sets are classes which implement 'AbstractFileSetCheck' interface. 127 * @param clazz class to check. 128 * @return true if a class may be considered as the checkstyle file set. 129 */ 130 public static boolean isFileSetModule(Class<?> clazz) { 131 return AbstractFileSetCheck.class.isAssignableFrom(clazz); 132 } 133 134 /** 135 * Checks whether a class may be considered as the checkstyle filter. 136 * Checkstyle's filters are classes which implement 'Filter' interface. 137 * @param clazz class to check. 138 * @return true if a class may be considered as the checkstyle filter. 139 */ 140 public static boolean isFilterModule(Class<?> clazz) { 141 return Filter.class.isAssignableFrom(clazz); 142 } 143 144 /** 145 * Checks whether a class may be considered as the checkstyle file filter. 146 * Checkstyle's file filters are classes which implement 'BeforeExecutionFileFilter' interface. 147 * @param clazz class to check. 148 * @return true if a class may be considered as the checkstyle file filter. 149 */ 150 public static boolean isFileFilterModule(Class<?> clazz) { 151 return BeforeExecutionFileFilter.class.isAssignableFrom(clazz); 152 } 153 154 /** 155 * Checks whether a class may be considered as the checkstyle audit listener module. 156 * Checkstyle's audit listener modules are classes which implement 'AuditListener' interface. 157 * @param clazz class to check. 158 * @return true if a class may be considered as the checkstyle audit listener module. 159 */ 160 public static boolean isAuditListener(Class<?> clazz) { 161 return AuditListener.class.isAssignableFrom(clazz); 162 } 163 164 /** 165 * Checks whether a class may be considered as the checkstyle root module. 166 * Checkstyle's root modules are classes which implement 'RootModule' interface. 167 * @param clazz class to check. 168 * @return true if a class may be considered as the checkstyle root module. 169 */ 170 public static boolean isRootModule(Class<?> clazz) { 171 return RootModule.class.isAssignableFrom(clazz); 172 } 173 174 /** 175 * Checks whether a class may be considered as the checkstyle {@code TreeWalker} filter. 176 * Checkstyle's {@code TreeWalker} filters are classes which implement 'TreeWalkerFilter' 177 * interface. 178 * @param clazz class to check. 179 * @return true if a class may be considered as the checkstyle {@code TreeWalker} filter. 180 */ 181 public static boolean isTreeWalkerFilterModule(Class<?> clazz) { 182 return TreeWalkerFilter.class.isAssignableFrom(clazz); 183 } 184 185}