code: /*
   * 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;
      }
  
  }
  