# Annotations der aufrufenden Methode ermitteln



## KingHale (28. Feb 2012)

Hi,

ich benötige eine Prüfung, ob die aufrufende Methode eine bestimmte Annotation hat und eventuell deren Wert.


```
@MyAnnotation( "someValue" )
void doSomething() {
        String str = getAnnotationValue();
}

String getAnnotationValue() {
	Throwable t = new Throwable();
	StackTraceElement[] elements = t.getStackTrace();

	String callerMethodName = elements[1].getMethodName();
	String callerClassName = elements[1].getClassName();
        Class cls = elements[1].getClass();
        return ?;
}
```

So weit so gut. Aber wie komme ich nun an die Annotation der Methode und deren Value?


----------



## Gast2 (28. Feb 2012)

Über das Class Objekt kannst du dir die passende Methode suchen, wenn du die hast kannst du per
Method (Java 2 Platform SE 5.0)
alle Annotations der Methode auslesen. Über die Annotation kommst du dann an den Wert der Annotation.

Aber:
Das ganze schaut, vorsicht formuliert, interessant aus. Und das meine ich nicht im positiven Sinn 
Was bezweckst du damit? Wollst du nur den Wert der Annotation auslesen und das in eine eigene Methode auslagern?


----------



## KingHale (28. Feb 2012)

Es geht um die Implementierung einer Security-Frameworks (das von EJB ist leider nicht zu gebrauchen). Dabei kann eine Methode mittels die Annotation "PermissionRequired" erhalten (oder eben auch nicht). Eine zentrale Methode (eben diese dort unten) prüft dann, ob der User die erforderliche Berechtigung besitzt. Somit kenne ich (Methode unten) die Signatur der aufrufenden Methode nicht und


```
elements
```

kennt leider keine Methode "getMethod" obwohl die Signatur ja im Stack vorhanden ist. Das Thema "Annotation" scheint mir in Java etwas unausgereift. Noch einfacher wäre hier ein Aufruf von


```
elements[idx].getAnnotations()
```
 was es leider auch nicht gibt


----------



## Gast2 (28. Feb 2012)

Du hast da halt einfach nur einen Stacktrace, der ist im Prinzip nur ne Ansammlung von Strings die dir sagen wo nen Fehler aufgetreten ist. Das ist meiner Meinung nach auch irgendwie der falsche Weg daran zu gehen.


```
Class cls = elements[1].getClass();
```
Das liefert dir auch nicht das was du dir erwartest. elements ist ein Array vom Typ StackTraceElement. 
	
	
	
	





```
cls
```
 wird bei dir also StackTraceElement sein und ist NICHT die Klasse aus der der Stacktrace kommt.

Ich weiß aber auch grad nicht ob man noch irgendwie anders an die Annotations kommt. Den Weg den ich kenne ist:
- Class objekt holen
- gewünschte Methoden holen
- getAnnotation(...) oder isAnnotationPresent(...) aufrufen.

Vielleicht weiß da jemand anderes noch was schlaueres


----------



## KingHale (28. Feb 2012)

Du hast schon soweit recht. Allerdings ist der Stacktrace genau die Referenz in die vom ClassLoader geladenen Klassen und Methoden. Leider fehlen einige Informationen.


----------



## DanZ (28. Feb 2012)

Mit dem Stracktrace wird das nicht so einfach (wenn nicht sogar fast unmöglich) (so wie EikeB schreibt klappt es zwar, aber nur wenn es nur eine Methode mit diesem Namen in der Klasse gibt und trotzdem musst du da noch dran rumparsen).

Allerdings frag ich mich grade: Du musst ja, damit das klappt, in jeder Methode, die gesichert ist, diese checkPermission Methode aufrufen... wo genau hast du dann noch den Vorteil mit der Annotation(vorallem wenn es nur eine gibt)?


----------



## KingHale (28. Feb 2012)

Ich hab was gefunden, was funktioniert. Falls sich noch jemand für eine brauchbare Security-Implementierung interessiert die Rollen von Rechten entkoppelt:

Some method in any class (e.g. a servlet or session bean) gets the user context. This call automatically checks if a permission is required to call that method at all:


```
@PermissionRequired
void someMethod( String sessionId, ...) {
  HaleSessionContext ctx = getSessionContext( sessionId );
 ...
}

public getSessionContext( String sessionId ) {
   //--- Check permission before returning context
   if ( isPermissionRequired( 2 )) {
      //--- if annotated then check permission here
   }
}

private String isPermissionRequired( int level ) {
	Throwable t = new Throwable();
	StackTraceElement[] elements = t.getStackTrace();
	String callerClassName = elements[level].getClassName();
	String callerMethodName = elements[level].getMethodName();

	PermissionRequired perm = null ;
	try {
		Method m = Class.forName(callerClassName ).getMethod( callerMethodName );
		perm = m.getAnnotation( PermissionRequired.class );
	} catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	//--- Calling method annotated => return class and method name
	if ( perm != null )
		return callerClassName + "." + callerMethodName ;

	//--- Calling method not annotated => return null
	return null;
}
```


----------



## DanZ (28. Feb 2012)

dir ist klar, dass das nur funktionier, wenn die Methode keine Parameter hat?


----------



## KingHale (28. Feb 2012)

Das Prinzip ist folgendes:

Ein User ist einer oder mehreren Rollen zugeordnet. Rollen und User können vom Administrator frei definiert werden. An einer Rolle hängen die erlaubten Aktionen. Eine Aktion ist ganz einfach "className.methodName". Dann müssen nur noch die Methoden, für die eine Permission erforderlich ist, diese als Annotation erhalten.

Alle diese Methoden sind Methoden des Servers, die von irgendeinem Client (WebService, WebFrontend, Swing-App oder sonstwas) aufgerufen werden können.

Schlank, leicht lesbar und vor allem vom Kunden anpassbar. Rollen werden nicht vom Entwickler festgelegt, sondern vom Kunden der Anwendung.

Übrigens scheint "getAnnotation()" nicht bei "private" Methoden zu funktionieren!?!


----------



## KingHale (28. Feb 2012)

hmmm. Das heisst, ich benötige entweder immer die gleiche Signatur bei den annotierten Methoden oder eine weitere Zwischenschicht. Ärgerlich


----------



## DanZ (28. Feb 2012)

nein guck mal Class#getDeclaredMethods an. Aber du darfst jeden Methodennamen pro Klasse nur einmal vergeben.

Warum reicht dir das EJB System nicht? EJBContext#isUserInRole() und ein eigener JAAS Provider sollten doch das gleiche tun?


----------



## KingHale (28. Feb 2012)

Hey prima: getMethods() liefert die Namen. OK die Einschränkung ist, das jeder Methodenname in einer Klasse nur einmal vorkommen darf, aber das passt.

EJBContext#isUserInRole() reicht eben gerade nicht. Dabei geht es ja um Rollen, die eigentlich der Kunde festlegen soll und nicht der Entwickler. Ich könnte natürlich statt Rollen einfach als Key "classname.methodname" eintragen, aber das würde jedes LDAP einer zentralen User-Verwaltung gigantisch aufblähen, da ja alle Permissions aller Anwendungen dort einzeln je User verwaltet werden müssten.

Dieser EJB-Ansatz ist ein rein theoretisches Modell, das für kleine Unternehmen funktioniert oder für Anwendungen, die wirklich nur ganz wenige Rollen haben, die dann schon der Enwickler codieren kann und die auch nicht dynamisch geändert werden müssen.


----------

