> classes) {
+ this.classes = classes;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Class extends Annotation>[] annotations() {
+ return new Class[] { Plugin.class };
+ }
+
+ @Override
+ public void reportTypeAnnotation(Class extends Annotation> annotation, String className) {
+ if (names.add(className)) {
+ try {
+ classes.add(this.getClass().getClassLoader().loadClass(className));
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ }
+ }
+ }
+ }
+}
diff --git a/core/src/net/sf/openrocket/plugin/JIJ.java b/core/src/net/sf/openrocket/plugin/JIJ.java
deleted file mode 100644
index 6d9fec052..000000000
--- a/core/src/net/sf/openrocket/plugin/JIJ.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.sf.openrocket.plugin;
-
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
-public class JIJ {
-
- public static void main(String[] args) throws Exception {
- String cp = System.getProperty("java.class.path");
- String[] cps = cp.split(File.pathSeparator);
-
- URL[] urls = new URL[cps.length + 1];
- for (int i = 0; i < cps.length; i++) {
- urls[i] = new File(cps[i]).toURI().toURL();
- }
- urls[cps.length] = new File("/home/sampo/Projects/OpenRocket/core/example.jar").toURI().toURL();
-
- System.out.println("Classpath: " + Arrays.toString(urls));
-
- URLClassLoader loader = new URLClassLoader(urls, null);
- Class> c = loader.loadClass("net.sf.openrocket.plugin.Test");
- Method m = c.getMethod("main", args.getClass());
- m.invoke(null, (Object) args);
- }
-
-}
diff --git a/core/src/net/sf/openrocket/plugin/Plugin.java b/core/src/net/sf/openrocket/plugin/Plugin.java
index de8eb4cdd..2dc2aee27 100644
--- a/core/src/net/sf/openrocket/plugin/Plugin.java
+++ b/core/src/net/sf/openrocket/plugin/Plugin.java
@@ -6,8 +6,10 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
- * Annotation that defines an interface to be a plugin interface.
- * Plugin interfaces are automatically discovered from plugin JARs and
+ * Annotation that defines an interface to be a plugin interface and
+ * classes as plugin implementations.
+ *
+ * Plugin interfaces are automatically discovered from the classpath and
* registered as plugins in Guice.
*
* @author Sampo Niskanen
diff --git a/core/src/net/sf/openrocket/plugin/PluginModule.java b/core/src/net/sf/openrocket/plugin/PluginModule.java
index 5aaa24404..c16289b18 100644
--- a/core/src/net/sf/openrocket/plugin/PluginModule.java
+++ b/core/src/net/sf/openrocket/plugin/PluginModule.java
@@ -1,14 +1,9 @@
package net.sf.openrocket.plugin;
-import java.io.File;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
@@ -21,63 +16,46 @@ import com.google.inject.multibindings.Multibinder;
*/
public class PluginModule extends AbstractModule {
- private final List jars;
- private final ClassLoader classLoader;
private Map, Multibinder>> binders = new HashMap, Multibinder>>();
-
-
- /**
- * Sole constructor.
- *
- * @param jars the JAR files to search for plugins
- * @param classLoader the class loader used to load classes from the JAR files
- */
- public PluginModule(List jars, ClassLoader classLoader) {
- this.jars = jars;
- this.classLoader = classLoader;
- }
-
-
- @Override
- protected void configure() {
- for (File jar : jars) {
- List classNames = readClassNames(jar);
- for (String className : classNames) {
- checkForPlugin(className);
- }
- }
- }
-
+ private AnnotationFinder finder = new AnnotationFinderImpl();
@SuppressWarnings("unchecked")
- private void checkForPlugin(String className) {
- try {
+ @Override
+ protected void configure() {
+
+ List> classes = finder.findAnnotatedTypes(Plugin.class);
+ List> interfaces = new ArrayList>();
+ List> unusedInterfaces;
+
+
+ // Find plugin interfaces
+ for (Class> c : classes) {
+ if (c.isInterface()) {
+ interfaces.add(c);
+ }
+ }
+ unusedInterfaces = new ArrayList>(interfaces);
+
+ // Find plugin implementations
+ for (Class> c : classes) {
+ if (c.isInterface())
+ continue;
- Class> c = classLoader.loadClass(className);
for (Class> intf : c.getInterfaces()) {
- System.out.println("Testing class " + c + " interface " + intf);
-
- if (isPluginInterface(intf)) {
- System.out.println("BINDING");
+ if (interfaces.contains(intf)) {
// Ugly hack to enable dynamic binding... Can this be done type-safely?
Multibinder