package ameba.scanner; import javassist.ClassPool; import javassist.CtClass; import javassist.NotFoundException; import org.apache.commons.lang3.ArrayUtils; import org.glassfish.jersey.internal.OsgiRegistry; import org.glassfish.jersey.internal.util.ReflectionHelper; import org.glassfish.jersey.server.internal.LocalizationMessages; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.lang.annotation.Annotation; import java.security.AccessController; import java.security.PrivilegedActionException; /** * <p>Abstract ClassInfo class.</p> * * @author icode * */ public abstract class ClassInfo { private static final Logger logger = LoggerFactory.getLogger(ClassInfo.class); private CtClass ctClass; private String fileName; private Object[] annotations; /** * <p>Constructor for ClassInfo.</p> * * @param fileName a {@link java.lang.String} object. */ public ClassInfo(String fileName) { this.fileName = fileName; } /** * <p>Getter for the field <code>fileName</code>.</p> * * @return a {@link java.lang.String} object. */ public String getFileName() { return fileName; } /** * <p>Getter for the field <code>ctClass</code>.</p> * * @return a {@link javassist.CtClass} object. */ public CtClass getCtClass() { if (ctClass == null && fileName.endsWith(".class")) { try { ctClass = ClassPool.getDefault().makeClass(getFileStream()); } catch (IOException e) { logger.error("make class error", e); } } return ctClass; } /** * <p>getClassName.</p> * * @return a {@link java.lang.String} object. */ public String getClassName() { return getCtClass().getName(); } /** * <p>Getter for the field <code>annotations</code>.</p> * * @return an array of {@link java.lang.Object} objects. */ public Object[] getAnnotations() { if (annotations == null) { try { annotations = getCtClass().getAvailableAnnotations(); } catch (Exception | Error e) { return new Object[0]; } } return annotations; } /** * <p>containsAnnotations.</p> * * @param annotationClass a {@link java.lang.Class} object. * @return a boolean. */ @SuppressWarnings("unchecked") @SafeVarargs public final boolean containsAnnotations(Class<? extends Annotation>... annotationClass) { if (ArrayUtils.isEmpty(annotationClass)) { return false; } for (Object anno : getAnnotations()) { for (Class cls : annotationClass) { if (((Annotation) anno).annotationType().equals(cls)) { return true; } } } return false; } /** * <p>accpet.</p> * * @param acceptable a {@link ameba.scanner.Acceptable} object. * @return a boolean. */ public boolean accpet(Acceptable<CtClass> acceptable) { boolean accept = checkSuperClass(getCtClass(), acceptable); if (!accept) accept = checkInterface(getCtClass(), acceptable); return accept; } private boolean checkSuperClass(CtClass superClass, Acceptable<CtClass> accept) { while (superClass != null && !superClass.getName().equals(Object.class.getName())) { if (accept.accept(superClass) || checkInterface(superClass, accept)) { return true; } try { superClass = superClass.getSuperclass(); } catch (NotFoundException e) { return false; } } return false; } private boolean checkInterface(CtClass interfaceClass, Acceptable<CtClass> accept) { try { for (CtClass ctClass : interfaceClass.getInterfaces()) { if (accept.accept(ctClass) || checkInterface(ctClass, accept)) { return true; } } } catch (NotFoundException e) { return false; } return false; } /** * <p>isPublic.</p> * * @return a boolean. */ public boolean isPublic() { return javassist.Modifier.isPublic(getCtClass().getModifiers()); } /** * <p>toClass.</p> * * @return a {@link java.lang.Class} object. */ public Class toClass() { return getClassForName(getCtClass().getName()); } /** * <p>getClassForName.</p> * * @param className a {@link java.lang.String} object. * @return a {@link java.lang.Class} object. */ public Class getClassForName(final String className) { try { final OsgiRegistry osgiRegistry = ReflectionHelper.getOsgiRegistryInstance(); if (osgiRegistry != null) { return osgiRegistry.classForNameWithException(className); } else { return AccessController.doPrivileged(ReflectionHelper.classForNameWithExceptionPEA(className)); } } catch (final ClassNotFoundException ex) { throw new RuntimeException(LocalizationMessages.ERROR_SCANNING_CLASS_NOT_FOUND(className), ex); } catch (final PrivilegedActionException pae) { final Throwable cause = pae.getCause(); if (cause instanceof ClassNotFoundException) { throw new RuntimeException(LocalizationMessages.ERROR_SCANNING_CLASS_NOT_FOUND(className), cause); } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else { throw new RuntimeException(cause); } } } /** * <p>startsWithPackage.</p> * * @param pkgs a {@link java.lang.String} object. * @return a boolean. */ public boolean startsWithPackage(String... pkgs) { for (String st : pkgs) { if (!st.endsWith(".")) st += "."; String className = getClassName(); if (className.startsWith(st)) { return true; } } return false; } /** * <p>getFileStream.</p> * * @return a {@link java.io.InputStream} object. */ public abstract InputStream getFileStream(); /** * <p>closeFileStream.</p> */ public abstract void closeFileStream(); }