Подтвердить что ты не робот

Как создать пользовательскую аннотацию с кодом

Я хотел бы создать свою собственную аннотацию. Моя структура - автономное Java-приложение. Когда кто-то аннотирует свой класс pojo, "скрытый" код позади вызывает методы.

Например, сегодня в Java EE имеется аннотация @MessageDriven. И когда вы комментируете свой класс с помощью @MessageDriven и, кроме того, реализуете интерфейс MessageListener, есть код, который вызывает onMessage(Message msg). когда сообщение приходит из очереди/темы.

Как создать аннотацию (@MyMessageDriven), которая может быть добавлена ​​в pojo, а также реализовать MyCustomMessageListener.

Результат, который я желаю, является триггером "скрытого" кода (моего), который вызовет метод реализованного интерфейса (точно так же, как он работает с образцом, который я написал ниже).

4b9b3361

Ответ 1

Я рекомендую прочитать эту запись в блоге вплоть до того момента, когда автор помнит, что у него есть доступ к сканированию компонентов Spring особенность.

Первоначальная проблема заключается в проверке пути к классу, чтобы найти классы с пользовательской аннотацией. Как только это будет сделано, у вас есть объекты в вашем автономном приложении, через которые с помощью object.getClass().getAnnotations() вы можете вставлять слушателей или настраивать поведение необходимо добавить к объектам, содержащим пользовательские аннотации.

Скажем, у вас есть следующая пользовательская аннотация:

@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMessageDriven {}

И вы используете его в своем приложении:

@MyMessageDriven
public class MyObject {}

Теперь, в соответствующем месте в вашем приложении, вы должны иметь способ выдавать все классы, несущие MyMessageDriven:

Set<Class<?>> findAllMessageDrivenClasses() {
  final StopWatch sw = new StopWatch();
  sw.start();
  final Reflections reflections = new Reflections("org.projectx", new TypeAnnotationsScanner());
  Set<Class<?>> allMessageDrivens = reflections.getTypesAnnotatedWith(MyMessageDriven.class); // NOTE HERE
  sw.stop();
  return allMessageDrivens;
}

Имея это, я предполагаю, что в вашем приложении есть точка, которая либо (1) имеет доступ к объектам в вашем приложении, либо (2) шаблон посетителя или итератора на всех объектах приложения. Итак, в какой-то момент я предполагаю, что у нас есть все целевые объекты как objects:

Set<Class<?>> msgDrivenClasses = findAllMessageDrivenClasses();
for (Object o : objects) {
  if (msgDrivenClasses.contains(o.getClass()) {
    invokeTheMessageListener(o);
  }
}

С другой стороны, должна существовать некоторая реализация MyMessageListener, которая доступна, когда найдены объекты, имеющие MyMessageDriven:

void invokeTheMessageListener(Object o) {
  theMessageListener.onMessage(o);
}

Этот ответ настроен на запись в блоге, поэтому, пожалуйста, обратитесь к блогу для настройки библиотек. И, наконец, не в последнюю очередь, это пример кода для проблемы, и он может быть реорганизован на более совместимый с шаблонами и элегантный стиль.

Обновить. Существует требование, чтобы целевые объекты должны были знать о своих собственных слушателях. Поэтому я бы предложил следующий подход. Пусть имеет интерфейс MyMessageListenerAware:

interface MyMessageListenerAware {
  MyMessageListener getMyMessageListener();
}

// and this is the original MyMessageListener
interface MyMessageListener {
  void onMessage(Object o);
}

Теперь целевые объекты должны реализовать указанный выше интерфейс:

class MySampleObject implements MyMessageListenerAware {

  public MyMesssageListener getMyMessageLisener() {
    return mySampleObjectImplementationOfMyMessageListener;
  }

}

При этом метод invokeTheMessageListener становится следующим:

void invokeMessageListener(Object o) {
  if (o instance MyMessageListenerAware) {
    MyMessageListener l = ((MyMessageListenerAware) o).getMyMessageListener();
    l.onMessage(o);
  }
}

Хотя, я настоятельно рекомендую прочитать Visitor или Strategy. То, что вы намереваетесь сделать, похоже на то, что вам нужно, чтобы определенные объекты реагировали/действовали/обрабатывались с общим объектом/событием в приложении, но каждый со своей собственной интерпретацией/алгоритмом/реализацией.

Ответ 2

создайте аннотацию примерно так:

 public @interface MyMessageDriven{
 }

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

public interface MyMessagListener {

    public void message();
}



@MyMessageDriven  
public class MyMessage implements MyMessagListener  {
   public void message(){
     System.out.println(" I am executed")
   }
} 

Загрузите вышеприведенный класс с помощью загрузчика классов и используя рефлексы, проверьте, что аннотация является прерентной.

если он присутствует, используйте загруженный экземпляр для его выполнения.

  Object obj = ClassLoader.getSystemClassLoader().loadClass("MyMessage").newInstance();
  MyMessagListener mml =  (MyMessagListener) obj;
  mml.message();

Реализация Listener, которую вы можете поместить в класс MyMessage или какой-либо другой класс, который реализует MessageListener.

В этом случае необходимо обеспечить реализацию для message() того, что он собирается делать.

Но этот класс должен быть загружен и более важным является то, как загружается ваш класс MyMessage.

Это основано на метаданных, присутствующих в классе MyMessage. Аналогичным образом, в сценарии реального времени это также работает.

Аннотации - это метаданные для класса, который говорит на основе предоставленных данных, что-то делать. Если эти метаданные не присутствуют в классе MyMessage, вам не нужно выполнять метод message().

Надеюсь, это поможет вам.