/* * Copyright (C) 2013 Samuel Halliday * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see [http://www.gnu.org/licenses/]. */ package com.github.fommil.netlib.generator; import lombok.Cleanup; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.java.Log; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import static com.google.common.collect.Lists.newArrayList; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; /** * Scans jar files for methods. * <p> * <b>SIDE-EFFECT WARNING: discovered classes are loaded</b> * (only point at trusted jars, as arbitrary code may be invoked). * * @author Sam Halliday */ @RequiredArgsConstructor @Log public class JarMethodScanner { @NonNull private final File file; private URLClassLoader createLoader() { try { URL url = file.toURI().toURL(); return new URLClassLoader(new URL[]{url}); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } } private List<String> getClasses(String packageName) throws IOException { @Cleanup JarFile jar = new JarFile(file); List<String> matched = newArrayList(); for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements(); ) { String entryName = entries.nextElement().getName(); if (entryName.startsWith(packageName.replace(".", "/")) && entryName.endsWith(".class")) matched.add(entryName.replace(".class", "").replace("/", ".")); } return matched; } public List<Method> getStaticMethods(String packageName) throws Exception { List<Method> methods = newArrayList(); List<String> classNames = getClasses(packageName); URLClassLoader loader = createLoader(); for (String className : classNames) { Class<?> clazz = loader.loadClass(className); for (Method method : clazz.getMethods()) { int modifiers = method.getModifiers(); String fqn = method.getDeclaringClass().getCanonicalName(); if (isStatic(modifiers) && isPublic(modifiers) && fqn.startsWith(packageName)) methods.add(method); } } return methods; } }