# Eigene Annotations auslesen von nachgeladenen Klassen



## Tilian (8. Juli 2010)

Hallo erstmal,

Ich habe folgendes Problem:
Ich bin dabei ein Plugin System zu Programmieren. Dabei lade Klassen mittels des URLClassloaders aus einem Jar File nach. Jede Klasse die sozusagen die main ist für das Plugin enthält. eine von mit definierte Annotation "Plugin" und es existieren weitere Annotations für den "Entry Point" usw... Doch wenn ich diese Klassen Nachlade werden die Annotations nicht ausgelesen.
Ich versuche die Annotations mittels getAnnotations() aus. Die Annotations sind in einem Interface definiert, welches von der jeweiligen Klasse implementiert wird. Dabei ist die Retention Policy auf Runtime gesetzt für jede Annotation.

Langsam frage ich mich ob die Annotations überhaupt mitgeladen werden.
Oder was mache ich Falsch beim Auslesen der Annotations?

Danke für eure Hilf


----------



## Akeshihiro (8. Juli 2010)

Also bei mir klappt folgendes super: Ich habe eine Annotation geschrieben, welche den Namen Plugin trägt und eine Eigenschaft entryPoint besitzt. entryPoint besitzt dabei die Bezeichnung der Methode, welche als Plug-Startpunkt fungieren soll. Dann habe ich ein Plugin geschrieben, welches TestPlugin heißt und auf das ich die Annotation Plugin angewendet habe. TestPlugin besitzt natürlich eine kleine Implementierung, damit man auch sieht, dass es arbeitet. Ich habe TestPlugin in eine Jar exportiert. Diese Jar wird dann mittels URLClassLoader geladen, ein Objekt instanziert und der entryPoint aufgerufen. Den entryPoint bzw. die Methode, welche als entryPoint dient, habe ich mit einem Rückgabewert vom Typ Object und mit einem Object-Array für die Parameter ausgestattet. Der Rückgabetyp ist für die Signatur eigentlich egal, aber die Parameter müssen stimmen, daher wäre es besser, wenn man noch ein Interface deklarieren würde, das alle Plugins implementieren müssen, dann wäre aber der Methodennamen festgelegt und man könnte sich das mit der Annontation sparen. Wäre aber sicherer und nicht so Fehleranfällig.

So, hier meine Sources. Über Packagenamen nicht wundern, hat Ordnungsgründe und das Ladeverfahren der Plugins ist hardcoded, aber ich werde jetzt auch keine dynamisch Routine für ein Beispiel zusammenschustern, ist schließlich nur ein fiktives Beispiel.
Plugin.java

```
package de.tutorials.trilian.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Plugin {
	String entryPoint() default "pluginMain";
}
```
TestPlugin.java

```
package de.tutorials.trilian.annotations;

@Plugin
public class TestPlugin {
	public Object pluginMain(Object[] args) {
		System.out.println("Testplugin gestartet");

		System.out.println("Parameter:");
		System.out.println("Anzahl: " + args.length);
		for(int i = 0; i < args.length; i++) {
			System.out.println(i + " => " + args[i].toString());
		}

		return null;
	}
}
```
AnnontationLoadingSample.java

```
package de.tutorials.trilian.annotations;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

public class AnnotationLoadingSample {
	public static void main(String[] args) throws MalformedURLException,
			ClassNotFoundException, InstantiationException,
			IllegalAccessException, SecurityException, NoSuchMethodException,
			IllegalArgumentException, InvocationTargetException {
		URLClassLoader loader = new URLClassLoader(new URL[]{new URL(
				"file://localhost/home/link/plugins.jar")});
		Class<?> pluginClass = loader.loadClass("de.tutorials.trilian.annotations.TestPlugin");
		Plugin pluginAnnotation = pluginClass.getAnnotation(Plugin.class);
		if(pluginAnnotation == null) { return; }

		Object plugin = pluginClass.newInstance();
		String entryPoint = pluginAnnotation.entryPoint();
		Object[] paramArgs = new Object[]{"param1", "param2"};
		Object[] methodParams = new Object[]{paramArgs};
		pluginClass.getMethod(entryPoint, Object[].class).invoke(plugin,
				methodParams);
	}
}
```

Ausgabe:


> Testplugin gestartet
> Parameter:
> Anzahl: 2
> 0 => param1
> 1 => param2



EDIT:
Habe mal noch ein Plugin gebastelt, das aber einen anderen entryPoint besitzt, um zu zeigen, dass man den entryPoint dynamisch für jedes Plugin festlegen kann und nicht den von Plugin festgelegten Standard-entryPoint verwenden muss.
TestPlugin2.java

```
package de.tutorials.trilian.annotations;

@Plugin(entryPoint = "meineMain")
public class TestPlugin2 {
	public Object meineMain(Object[] args) {
		System.out.println("Methode meineMain aus TestPlugin2 aufgerufen.");
		
		return null;
	}
}
```
Nun habe ich halt beide Plugin-Klassen in plugins.jar exportiert, damit beide vorhanden sind.
In AnnotationLoadingSample.java muss dann die Zeile


> Class<?> pluginClass = loader.loadClass("de.tutorials.trilian.annotations.TestPlugin");


gegen


> Class<?> pluginClass = loader.loadClass("de.tutorials.trilian.annotations.TestPlugin2");


geändert werden, damit die neue Plugin-Klasse geladen wird.
Ausgabe:


> Methode meineMain aus TestPlugin2 aufgerufen.


----------

