Можно ли добавлять аннотации к методам или элементам, использующим AOP-фреймворки?

java aop

129 просмотра

1 ответ

56 Репутация автора

Могу ли я использовать AOP (AspectJ, Guice или другое) для добавления аннотаций к классам, которые я не могу изменить? Моим первым вариантом использования было бы добавление постоянных и обязательных аннотаций. Я знаю, что могу написать файлы конфигурации XML для JPA и JAXB, но я не знаю ни одного способа сделать это для привязки JSON.

Я искал несколько примеров / руководств, но не нашел ничего, демонстрирующего это. Возможно ли это, и если да, может ли кто-нибудь привести хороший пример или еще лучше указать мне на некоторые ресурсы?

Автор: user1723105 Источник Размещён: 18.07.2016 04:09

Ответы (1)


0 плюса

36691 Репутация автора

Решение

Да, вы можете использовать AspectJ для этой цели (цитирование шпаргалки AspectJ , см. Также тетрадь разработчика AspectJ Development Kit ):

  • declare @type: C : @SomeAnnotation;
    объявляет аннотацию @SomeAnnotationк типу C.
  • declare @method: * C.foo*(..) : @SomeAnnotation;
    объявляет аннотацию @SomeAnnotationдля всех методов, объявленных в Cначале foo.
  • declare @constructor: C.new(..) : @SomeAnnotation;
    объявляет аннотацию @SomeAnnotationдля всех конструкторов, объявленных в C.
  • declare @field: * C.* : @SomeAnnotation;
    объявляет аннотацию @SomeAnnotationдля всех полей, объявленных в C.

На всякий случай, если вы хотите спросить: эта функция поддерживается только в собственном синтаксисе AspectJ, а не в синтаксисе @AspectJ в стиле аннотаций.


Обновление: вот пример кода, показывающего

  • как добавлять аннотации к классам, интерфейсам и методам,
  • что даже пометки, помеченные как @Inherited, наследуются только от класса к подклассу, никогда от интерфейса к классу и никогда к методам подкласса (типичное предостережение Java, о котором многие разработчики не знают, см. Эмуляция наследования аннотаций для интерфейсов и методов с AspectJ для объяснения и возможного обходной путь),
  • как с помощью AspectJ вы можете применить аннотацию к классам , реализующих интерфейс через +подкласс спецификатор, например , в MyInterface+,
  • как другой аспект может сразу увидеть и использовать аннотации, добавленные через declare @typeи declare @methodт. д.

Иерархия классов, включая абстрактные базовые классы и интерфейс:

package de.scrum_master.app;

public interface MyInterface {
    void doSomething();
    int doSomethingElse(int a, int b);
    String sayHelloTo(String name);
}
package de.scrum_master.app;

public abstract class NormalBase implements MyInterface {
    @Override
    public abstract void doSomething();

    @Override
    public int doSomethingElse(int a, int b) {
        return a + b;
    }

    @Override
    public abstract String sayHelloTo(String name);
}
package de.scrum_master.app;

public class Normal extends NormalBase {
    @Override
    public void doSomething() {
        //System.out.println("Doing something normal");
    }

    @Override
    public String sayHelloTo(String name) {
        return "A normal hello to " + name;
    }

    public void doNothing() {
        //System.out.println("Being lazy in a normal way");
    }
}
package de.scrum_master.app;

public abstract class SpecialBase {
    public abstract void doFoo();
    public abstract void makeBar();
}
package de.scrum_master.app;

public class Special extends SpecialBase implements MyInterface {
    @Override
    public void doSomething() {
        //System.out.println("Doing something special");
    }

    @Override
    public int doSomethingElse(int a, int b) {
        return a * b;
    }

    @Override
    public String sayHelloTo(String name) {
        return "A special hello to " + name;
    }

    @Override
    public void doFoo() {
        //System.out.println("Doing foo");
    }

    @Override
    public void makeBar() {
        //System.out.println("Making bar");
    }

    public int doZot() {
        return 11;
    }

    public String makeBlah() {
        return "Blah";
    }
}
package de.scrum_master.app;

public class SpecialTwo extends SpecialBase {
    @Override
    public void doFoo() {
        //System.out.println("Doing foo");
    }

    @Override
    public void makeBar() {
        //System.out.println("Making bar");
    }

    public String doXxx() {
        return "Xxx";
    }

    public int makeBlah() {
        return 22;
    }
}

Приложение-драйвер, создающее все виды объектов, вызывающее все виды методов:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        System.out.println("Normal instance");
        Normal normal = new Normal();
        normal.doSomething();
        normal.doSomethingElse(3, 5);
        normal.sayHelloTo("John");
        normal.doNothing();

        System.out.println("\nNormal instance as NormalBase");
        NormalBase normalBase = normal;
        normalBase.doSomething();
        normalBase.doSomethingElse(3, 5);
        normalBase.sayHelloTo("John");

        System.out.println("\nNormal instance as MyInterface");
        MyInterface myInterface = normal;
        myInterface.doSomething();
        myInterface.doSomethingElse(3, 5);
        myInterface.sayHelloTo("John");

        System.out.println("\nSpecial instance");
        Special special = new Special();
        special.doSomething();
        special.doSomethingElse(7, 8);
        special.doFoo();
        special.doZot();
        special.makeBar();
        special.makeBlah();
        special.sayHelloTo("Jane");

        System.out.println("\nSpecial instance as SpecialBase");
        SpecialBase specialBase = special;
        specialBase.doFoo();
        specialBase.makeBar();

        System.out.println("\nSpecial instance as MyInterface");
        myInterface = special;
        myInterface.doSomething();
        myInterface.doSomethingElse(7, 8);
        myInterface.sayHelloTo("Jane");

        System.out.println("\nSpecialTwo instance");
        SpecialTwo specialTwo = new SpecialTwo();
        specialTwo.doFoo();
        specialTwo.makeBar();
        specialTwo.makeBlah();
        specialTwo.doXxx();

        System.out.println("\nSpecialTwo instance as SpecialBase");
        specialBase = specialTwo;
        specialBase.doFoo();
        specialBase.makeBar();
    }
}

Некоторые аннотации маркеров позже будут добавлены в интерфейсы, классы, методы аспектом:

package de.scrum_master.app;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InterfaceMarker {}
package de.scrum_master.app;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface ClassMarker {}
package de.scrum_master.app;

import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MethodMarker {}

Аспект добавления аннотаций к интерфейсам, классам, методам:

package de.scrum_master.aspect;

import de.scrum_master.app.ClassMarker;
import de.scrum_master.app.InterfaceMarker;
import de.scrum_master.app.MethodMarker;
import de.scrum_master.app.MyInterface;
import de.scrum_master.app.SpecialBase;

public aspect AnnotationGenerator {
    declare @type : MyInterface+ : @InterfaceMarker;
    declare @type : SpecialBase : @ClassMarker;
    declare @method : * say*(..) : @MethodMarker;
}

Инициализация регистрации аспектов аннотированных классов и выполнение аннотированных методов:

package de.scrum_master.aspect;

import de.scrum_master.app.ClassMarker;
import de.scrum_master.app.InterfaceMarker;
import de.scrum_master.app.MethodMarker;

public aspect MarkedObjectLogger {
    before() : @annotation(InterfaceMarker) {
        System.out.println(thisJoinPoint + " -> @InterfaceMarker");
    }

    before() : @annotation(ClassMarker) {
        System.out.println(thisJoinPoint + " -> @ClassMarker");
    }

    before() : @annotation(MethodMarker) && execution(* *(..)) {
        System.out.println(thisJoinPoint + " -> @MethodMarker");
    }
}

Консольный журнал:

Normal instance
staticinitialization(de.scrum_master.app.NormalBase.<clinit>) -> @InterfaceMarker
staticinitialization(de.scrum_master.app.Normal.<clinit>) -> @InterfaceMarker
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> @MethodMarker

Normal instance as NormalBase
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> @MethodMarker

Normal instance as MyInterface
execution(String de.scrum_master.app.Normal.sayHelloTo(String)) -> @MethodMarker

Special instance
staticinitialization(de.scrum_master.app.SpecialBase.<clinit>) -> @ClassMarker
staticinitialization(de.scrum_master.app.Special.<clinit>) -> @InterfaceMarker
staticinitialization(de.scrum_master.app.Special.<clinit>) -> @ClassMarker
execution(String de.scrum_master.app.Special.sayHelloTo(String)) -> @MethodMarker

Special instance as SpecialBase

Special instance as MyInterface
execution(String de.scrum_master.app.Special.sayHelloTo(String)) -> @MethodMarker

SpecialTwo instance
staticinitialization(de.scrum_master.app.SpecialTwo.<clinit>) -> @ClassMarker

SpecialTwo instance as SpecialBase

Попробуйте удалить +from declare @type : MyInterface+и посмотрите, как @InterfaceMarkerисчезают все строки журнала с упоминанием, потому что аннотации интерфейса действительно не наследуются реализующими классами.

Автор: kriegaex Размещён: 23.07.2016 09:28
Вопросы из категории :
32x32