Mittels Annotations Methoden "erweitern"?

dunhillone

Mitglied
Hi

Ich versuche gerade etwas mit Annotations zu basteln. Die Idee wäre, dass für eine Methode eine sog. @SecurityCheck Annotation hinzugefügt werden kann. Diese sollte bewirken, dass vor oder nach dem Aufruf der Methode ein check auf die aktuellen Userdaten gemacht wird.

Irgendwie krieg ich es nicht so richtig hin. Das deklarieren der Annotation ist simpel, jedoch die Implementierung??


Hier mal der Code bisher..

Deklaration:
Java:
@Retention( RetentionPolicy.RUNTIME ) 
@Target(ElementType.METHOD)
public @interface SecurityCheck {
	/**
	 * Name of the user variable. Needs to be present in the methods attributes.
	 */
	String userVariable();
	
	/**
	 * When should the security check be done? Before or after the call (after means the return value is checked)
	 */
	SecurityCheckType type() default SecurityCheckType.BEFORE;
	
	/**
	 * For what role should be tested? (read/write/delete)
	 */
	Role role() default Role.READ;
}

Und Klasse welche die Annotation braucht:

Java:
public class BusinessService {

	/**
	 * Delete a business object.
	 */
	@SecurityCheck(role=Role.DELETE,type=SecurityCheckType.BEFORE,userVariable="securityObject")
	public void deleteBusinessObject(IBusinessObject businessObject, ISecurityObject securityObject) {
		
		// this body should not be executed until the security check is done...
		
	}
}

Was jetzt halt noch fehlt ist die implementierung der Annotation und wie und was ich wo im Programmablauf einfügen muss, um
die Annotation auch zu verwenden.

Bitte klärt mich auf, auch bezüglich, ob mein Vorhaben Sinnvoll ist..
 

madboy

Top Contributor
Willst du das alles selber machen oder hast du ein Problem mit einer Library, die die annotations für dich auslesen soll?
Wie dem auch sei: für mich sieht das sehr nach AOP aus und da gibt es ein paar Frameworks, sodass du das Rad nicht neu erfinden musst. Suche mal nach aspectj oder allgemeiner nach "Java aop", da sollte was dabei sein.
 

dunhillone

Mitglied
Willst du das alles selber machen oder hast du ein Problem mit einer Library, die die annotations für dich auslesen soll?
Wie dem auch sei: für mich sieht das sehr nach AOP aus und da gibt es ein paar Frameworks, sodass du das Rad nicht neu erfinden musst. Suche mal nach aspectj oder allgemeiner nach "Java aop", da sollte was dabei sein.

Ursprünglich wollte ich es mal selber implementieren. Mit AOP kenne ich mich nicht aus. Wäre wahrscheinlich auch zu spät, der Rest des Projektes ist normales Java. Da jetzt umzustellen wegen einem kleinen Teil.. denke das lohnt sich nicht.

Ich wollte jetzt mal mit eignen Annotations was basteln.. Keine Ahnung.. vileicht habe ich auch das Prinzip noch nicht ganz gerafft;)

Wenn nicht dann lassen ich es so wies ist. Gibt dann halt pro Methode ein par Zeilen Code mehr indem ich die Methoden für den Security Check direkt aufrufe..
 

byte

Top Contributor
Funktionserweiterungen mittels eigener Annotations lassen sich mit AspectJ ziemlich leicht realisieren. Hier ein Beispiel für obige SecurityCheck Annotation:

Java:
@Aspect
public class SecurityManager {
    
    @Before(
            value="execution(public * de.foobar.secured..*.*(..)) && @annotation(secured)",
            argNames="secured")
    public void doAccessCheck(SecurityCheck secured) {
        // Prüfen, ob Nutzer die nötige Rolle hat. Falls nein: Exception werfen
    }
    
}

Der Pointcut würde alle öffentlichen Methoden erweitern, die sich im Package de.foobar.secured befinden und mit SecurityCheck annotiert sind.

Man hat natürlich noch viel mehr Möglichkeiten (@Around, @After, ...) und kommt bei Bedarf auch an das Objekt und die Parameter ran, falls man das braucht.
 

byte

Top Contributor
Steht doch im Code! Das Annotation Objekt wird als Parameter übergeben. Da kannst Du alle Informationen auslesen, also in Deinem Fall z.B. die Rollen.
 

kay73

Bekanntes Mitglied
Hier ist eine alternative Implementierung dieser Auswertung von Annotationen.

Ich habe damals etwas Vergleichbares implementiert aber habe mich gegen AspectJ entschieden, weil die einzige Möglichkeit, die Ausführung des geschützten Codes zu verhindern ist, eine
Code:
Exception
zu werfen. Außerdem braucht es einen Weaver, der zusätzlich nach dem Compiler laufen muss. Außerdem wird AspectJ eigentlich nur als Eclipse-Plugin vernünftig unterstützt.

Wenn man auf die ausgefeilteren Features von AspectJ verzichten kann und die CGLIB verwendet, hat man IMHO deutlich interessantere und flexiblere Möglichkeiten, z. B. kann man den Methodenaufruf sauber auf ein alternatives Objekt umlenken, beliebige andere Werte zurückgeben oder eben per
Code:
Exception
aussteigen, wenn es sein muss.

Hier ist ein Beispiel, wie man einer Klasse zur Laufzeit beliebige neue Eigenschaften verpassen und diese nach der Erzeugung innerhalb Ereignisbehandlung beim Antreffen der Annotation nutzen kann. AspectJ kann das auch, allerdings nicht zur Laufzeit.

Man beachte, dass die Klasse
Code:
MyClassToBeSecured
niemals
Code:
RiskLevel
implementiert, aber die neue Eigenschaft trotzdem beim Antreffen der Annotation
Code:
SecurityCheck
ausgewertet wird. Derjenige, der
Code:
MyClassToBeSecured
implementiert, muss gar nicht wissen, dass es
Code:
RiskLevel
gibt.

Das Beispiel braucht die cglib-2.2.jar-Bibliothek im Klassenpfad.
Java:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface SecurityCheck {
    int riskLevel() default 10;
}

class MyClassToBeSecured {

    @SecurityCheck(riskLevel=20)
    public void higlySecureOperation() {
        System.out.println("higlySecureOperation!");
    }

    @SecurityCheck(riskLevel=50)
    public void normalOperation() {
        System.out.println("normalOperation...");
    }
}

public class SecurityDemo {

    public static void main(String [] args) {

        MyClassToBeSecured ops = SecureProxyFactory.createSecureProxy(MyClassToBeSecured.class);

        ((RiskLevel)ops).setRiskLevel(25);
        ops.higlySecureOperation();
        ops.normalOperation();

        ((RiskLevel)ops).setRiskLevel(15);
        ops.higlySecureOperation();

        ((RiskLevel)ops).setRiskLevel(-1);
        ops.normalOperation();
    }
}

interface RiskLevel {
    public void setRiskLevel(int level);
}

class SecureProxyFactory {
    
    private static class RiskLevelMethodInterceptor implements MethodInterceptor {
        
        private int riskLevel;
        
        public Object intercept(final Object o, final Method method, final Object[] os, final MethodProxy mp) throws Throwable {

            final String methodName = method.getName();

            if(methodName.equals("setRiskLevel")) {
                riskLevel=(Integer)os[0];
                return null;
            }

            if (method.isAnnotationPresent(SecurityCheck.class)) {

                int methodRiskLevel = method.getAnnotation(SecurityCheck.class).riskLevel();
                
                if(riskLevel > methodRiskLevel) {
                    System.out.println("Intercepted operation: "+methodName+", method risk: "+methodRiskLevel+", current risk: "+riskLevel+": Risk too high!");
                    return null;
                }

                if(riskLevel < 0) {
                    System.out.println(riskLevel+": Illegal risk level!");
                    throw new RuntimeException("Highest risk!");
                }
                
                System.out.println("Intercepted operation: "+methodName+", method risk: "+methodRiskLevel+", current risk: "+riskLevel+": Risk ok.");
            }

            return mp.invokeSuper(o, os);
        }
    }
    
    public static <T> T createSecureProxy(final Class<T> clazz) {
        
        final List<Class<?>> interfaces = new ArrayList<Class<?>>(Arrays.asList(clazz.getInterfaces()));
        interfaces.add(RiskLevel.class);
        
        return (T) Enhancer.create(clazz,
                interfaces.toArray(new Class<?>[]{}),
                new RiskLevelMethodInterceptor());
    }
}
Die Exception fliegt erst zuletzt:
Code:
Intercepted operation: higlySecureOperation, method risk: 20, current risk: 25: Risk too high!
Intercepted operation: normalOperation, method risk: 50, current risk: 25: Risk ok.
Exception in thread "main" java.lang.RuntimeException: Highest risk!
        at SecureProxyFactory$RiskLevelMethodInterceptor.intercept(SecurityDemo.java:81)
        at MyClassToBeSecured$$EnhancerByCGLIB$$14e3b52.normalOperation(<generated>)
        at SecurityDemo.main(SecurityDemo.java:47)
normalOperation...
Intercepted operation: higlySecureOperation, method risk: 20, current risk: 15: Risk ok.
higlySecureOperation!
-1: Illegal risk level!
 
Zuletzt bearbeitet:

byte

Top Contributor
Außerdem wird AspectJ eigentlich nur als Eclipse-Plugin vernünftig unterstützt.

Falsch. AspectJ wird z.B. auch durch Spring unterstützt, wenn man Load Time Weaving nutzt. Du kannst AspectJ problemlos ohne Eclipse OSGi verwenden. Einfach das Jar in den Classpath und fertig.

Wenn man auf die ausgefeilteren Features von AspectJ verzichten kann und die CGLIB verwendet, hat man IMHO deutlich interessantere und flexiblere Möglichkeiten, z. B. kann man den Methodenaufruf sauber auf ein alternatives Objekt umlenken, beliebige andere Werte zurückgeben oder eben per Exception aussteigen, wenn es sein muss.

Das geht mit AspectJ auch alles. Wenn Du in einem @Before Advice eine Exception wirfst, dann wird die eigentliche Methode nicht mehr ausgeführt. Wenn Du einen @Around Advice benutzt, kannst Du problemlos auf ein anderes Objekt delegieren, statt die eigentliche Methode aufzurufen.


Übrigens: Wenn man kein Load Time Weaving benutzen will, kann man auch ganz einfach JDK Proxies verwenden. Dann braucht man gar keine externe Lib. ;)
 

dunhillone

Mitglied
Das Thema ist erst mal nach hinten verschoben.. leider :( es warten dringendere Angelegenheiten.

Habe mich jetzt aber in erster Instanz mal für AspectJ entschieden, auch weil die Application mal auf Spring laufen wird.

Danke für die Tips bis hierhin.
 

kay73

Bekanntes Mitglied
Habe mich jetzt aber in erster Instanz mal für AspectJ entschieden, auch weil die Application mal auf Spring laufen wird.
Grundaetzlich parst Spring aber nur die @AspectJ-Annotationen und verwendet normalerweise Standard-Java-Proxies (wie byte u. a. vorschlaegt) oder alternativ CGLIB-Proxies (wie mein Code). Fuer echtes AspectJ ist Zusatzgefummel notwendig. Aber das wirst Du wahrscheinlich eh nicht brauchen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Übergabe eines Sortierkriteriums für ein Artikel Array mittels BiPredicate<Artikel, Artikel> Allgemeine Java-Themen 13
N Value Wert aus HTML-Button mittels thymeleaf spring an java übergeben Allgemeine Java-Themen 2
N Lottowebsite programmieren mittels Java, HTML,.... Allgemeine Java-Themen 7
W PDFs signieren mittels IText / Lowagie Allgemeine Java-Themen 0
Zrebna Möglichkeit regelmäßige indentation mittels/innerhalb Stringbuilder Allgemeine Java-Themen 14
J RotSchwarzBaum: Löschen mittels insert-Methode Allgemeine Java-Themen 20
LimDul Mittels Streams aus Strings A B C den String A, B und C machen Allgemeine Java-Themen 12
X Brüche kürzen mittels Methoden und ggT Allgemeine Java-Themen 15
D HTTP Http-Link mittels GUI schreiben Allgemeine Java-Themen 5
B Java Sternchen ausgeben mittels Rekursion Allgemeine Java-Themen 3
J GUI-Einstellungen mittels Preferences Allgemeine Java-Themen 6
Todesbote JFileChooser im Vordergrund (*.jar wird mittels shell_exec in PHP aufgerufen) Allgemeine Java-Themen 1
E Videosequenz mittels Java aus Video schneiden Allgemeine Java-Themen 10
B Ordner öffnen mittels Java in Linux-Umgebung Allgemeine Java-Themen 7
I Webseite auslesen (welche mittels Javascript Inhalt einbindet) Allgemeine Java-Themen 4
T HTML Tag Position mittels Pattern ermitteln Allgemeine Java-Themen 7
RySa Variablenname mittels Reflexions rausbekommen (als String) ? Allgemeine Java-Themen 9
U Classpath DLLs mittels System.load() laden: Allgemeine Java-Themen 6
T Wie rufe ich mittels String-Inhalts eine Methode auf? Allgemeine Java-Themen 3
T Exif mittels Java auslesen Allgemeine Java-Themen 14
A Sudoku mittels Backtracking Problem Allgemeine Java-Themen 6
7 Webseiten mittels Java auslesen Allgemeine Java-Themen 7
H Zwei verschiedene Dateien mittels einem Binärstream übertragen? Allgemeine Java-Themen 13
S Mittels eines Applets Bilder generieren die in einer Webseite angezeigt werden..? Allgemeine Java-Themen 8
X String zerlegen mittels regulärem Ausdruck Allgemeine Java-Themen 31
O Programm mittels Java installieren Allgemeine Java-Themen 15
S Array-Sort mittels Binärsuche Allgemeine Java-Themen 2
J Setter mittels invoice aufrufen Allgemeine Java-Themen 4
S Eingabeprüfung mittels Regexp Allgemeine Java-Themen 5
J Objekt in Datei speichern mittels Streams Allgemeine Java-Themen 6
D Einfaches Nutzen von Plugins mittels generischer Methode Allgemeine Java-Themen 3
E Aus mehreren PDFs eines machen, zusammenfügen mittels iText Allgemeine Java-Themen 1
G Graph mittels Punkte erstellen Allgemeine Java-Themen 27
M Problem bei PDF-Anzeige mittels Acrobat Viewer Bean Allgemeine Java-Themen 2
G HTML Code aus String mittels REGEX entfernen Allgemeine Java-Themen 2
spacegaier Performanceproblem beim Einlesen aus Datei mittels Threads Allgemeine Java-Themen 23
G Screenshot mittels robot ausführen Allgemeine Java-Themen 4
B Html Formulare mittels Java automatisch senden Allgemeine Java-Themen 5
E import mittels Eclipse Allgemeine Java-Themen 3
F mittels Collection<A> an A.class kommen? Allgemeine Java-Themen 7
T IF Abfrage + YES_NO Option mittels JOptionPane Allgemeine Java-Themen 3
F Zugriff mittels getObject() oder this.object ? Allgemeine Java-Themen 8
J Tonbalance mittels JMF regeln Allgemeine Java-Themen 3
G Font mittels ClassLoader in .jar wirft NotFoundException Allgemeine Java-Themen 10
R Interface mittels Reflection implementieren Allgemeine Java-Themen 8
G eigener logger mittels classe (dynamische logfilename) log4j Allgemeine Java-Themen 15
K Mittels Generics eine Methode verallgemeinern Allgemeine Java-Themen 2
A FTPS bzw. FTP over SSL mittels Java Allgemeine Java-Themen 9
Y komprimierung mittels Huffman-Algorithmus, bit-shifting. Allgemeine Java-Themen 2
G mysql datum umwandeln mittels jsp Allgemeine Java-Themen 10
F Hilfe: Adjazenzmatrix mittels JUnit testen. Allgemeine Java-Themen 2
Natorion Erkennen ob das Programm mittels Jar-Datei oder class . Allgemeine Java-Themen 9
P E-Mails mittels POP3 abrufen Allgemeine Java-Themen 2
S mail von server mittels mailapi löschen Allgemeine Java-Themen 2
T Java Class Intrumentation mit Annotations in Laufzeit Allgemeine Java-Themen 1
hdi Zu Reflections & Annotations Allgemeine Java-Themen 10
C Polymorphie Fragen zur Annotations von Persistenz Allgemeine Java-Themen 2
L Annotations um Gültigkeit von Attributen zu definieren? Allgemeine Java-Themen 4
K Annotations der aufrufenden Methode ermitteln Allgemeine Java-Themen 11
ruutaiokwu junit mit annotations geht nicht? Allgemeine Java-Themen 5
N Method-Annotations in aufgerufener Methode auswerten Allgemeine Java-Themen 2
W Annotations selbst erstellen und auswerten Allgemeine Java-Themen 4
V Reflection - Field-Instanz und Annotations Allgemeine Java-Themen 6
Landei Annotations ableiten Allgemeine Java-Themen 2
G Annotations. warum ? Allgemeine Java-Themen 9
L Annotations mit Vererbung Allgemeine Java-Themen 4
H eigene Annotations Allgemeine Java-Themen 2
byte Annotations: Arrays auslagern Allgemeine Java-Themen 2
G @Annotations Allgemeine Java-Themen 2
B Leere vererbte Interface-Methoden Allgemeine Java-Themen 8
R Programm führt Methoden gleichzeitig aus Allgemeine Java-Themen 2
Encera Unterschied zweier "toString"-Methoden Allgemeine Java-Themen 1
torresbig Klasse mit extends Calendar über Methoden ändern (Hirnblockade) Allgemeine Java-Themen 7
Sachinbhatt Sind alle Methoden in Java implizit virtuell Allgemeine Java-Themen 2
B Arrays von Methoden möglich? Allgemeine Java-Themen 44
S Mit Methoden kann man definieren für was <T> steht. Geht das auch irgendwie für Variablen? Allgemeine Java-Themen 12
N abstracte klassen methoden Allgemeine Java-Themen 32
G Methoden für die Zukunft sinnvoll? Allgemeine Java-Themen 4
nonickatall Methoden Kann man Klassen/Methoden aus Variablen heraus aufrufen? Allgemeine Java-Themen 6
LimDul Hä? Lambda-Ausdruck geht, Methoden-Referenz nicht Allgemeine Java-Themen 8
B Methoden Java Getter und Setter Methoden Allgemeine Java-Themen 9
Y Java Methoden unterschiedliche Zahlenreihen Allgemeine Java-Themen 2
S Interface Design von HookUp oder Callback Methoden für eigenes Framework Allgemeine Java-Themen 9
F Sich automatisch aufrufende Java-Methoden Allgemeine Java-Themen 2
J Namen von Methoden über Reguläre Ausdrücke bearbeiten Allgemeine Java-Themen 6
D Methoden Methoden anpassen und fehlende Funktionen hinzufügen Allgemeine Java-Themen 475
V Threads Probleme beim Aufrufen von Methoden einer anderen Klasse (Threads) Allgemeine Java-Themen 14
R Statistische Methoden (Mathematik) Aufgabe Allgemeine Java-Themen 9
L Operatoren Java Reflections: Alle Methoden einer Klasse aufrufen ohne Exceptions Allgemeine Java-Themen 5
L mehrere Methoden Allgemeine Java-Themen 19
KeexZDeveoper Zugriff auf Methoden vom Server Allgemeine Java-Themen 7
B StAX Parser - mehrere Methoden, ein XML Allgemeine Java-Themen 4
F Operationen/Methoden einen WebService im Browser mit Apache Axis aufrufen Allgemeine Java-Themen 4
A Automatisches Methoden Laufzeiten logging? Allgemeine Java-Themen 7
M Quellcode von Java-Methoden Allgemeine Java-Themen 9
rentasad Design-Frage - Interfaces, Klassen, statische Methoden Allgemeine Java-Themen 3
N HashMap und Methoden richtig einbinden Allgemeine Java-Themen 2
R Variable durch mehrere Methoden ändern und nutzen Allgemeine Java-Themen 17
Q-bert Methoden Methoden in Java Allgemeine Java-Themen 13
D Methoden Java-Aufgabe Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben