LINUX.ORG.RU

Beans и обработка событий изменения свойств

 


0

2

Привет. Есть у меня самописный набор классов а-ля Java Beans, т.е.:

class DummyBean
{
  private String m_str_prop;
  private List<PropertyListener> m_listeners;
  
  @PropertyAccessor
  public String getStringProp()
  {
    return m_str_prop;
  }

  @PropertyAccessor
  public void setStringProp(String a_str)
  {
    if(!m_str_prop.equals(m_str_prop = a_str))
    {
	// дергаем слушателей
	firePropertyChangeEvent();
    }
  }
  // ...
  public void addPropertyListener(PropertyListener l)
  {
    // ...
  }
  
  public void firePropertyChangeEvent()
  {
    // ...
  }
  // далее код анализа свойств бина и доступа к ним по строковому ИД (см. пояснение)
}
Т.е. бин с одним свойством «StringProp» типа String, при изменении которого должны оповещаться слушатели. За последнее ответственен метод firePropertyChangeEvent(), который, как видно, не имеет информации о том, какое именно свойство было изменено (предположим таки, что свойств у нас более одного).
Задача сделать так, чтобы вышеупомянутый метод каким-то образом сообщал слушателям идентификатор события.
Внимательный ЛОРовец наверняка заметил аннотацию PropertyAccessor. Это велосипед, который позволяет занести свойства бина в мап, чтобы пользователь мог применить оба способа изменения свойства:
DummyBean db = new DummyBean();
db.setProperty("StringProp","new value"); // первый способ
db.setStringProp("new value"); // второй способ
Вся магия заключается в том, что класс бина через Reflection ищет у себя методы, помеченные аннотацией, и, разделяя эти методы на геттеры и сеттеры, а так же определяя имя свойства по имени метода, заносит все это в мап, чтобы пользователь мог воспользоваться «первым» из способов.
Напомню задачу, нужно чтоб слушатели события изменения свойства получали его идентификатор. Решение проблемы очевидно (с самого начала :) ):
...
  @PropertyAccessor
  public void setStringProp(String a_str)
  {
    if(!m_str_prop.equals(m_str_prop = a_str))
    {
	// дергаем слушателей
	firePropertyChangeEvent("StringProp");
    }
  }

  public void firePropertyChangeEvent(String a_prop_id)
  {
    // ...
  }
...
Но это совершенно не круто, у нас могут быть десятки бинов, у каждого из которых пара десятков свойств, нехорошо заставлять программиста руками писать строковый ИД свойства в каждом сеттере, когда эта же информация уже есть в имени метода!
Извиняюсь за простыню, надеюсь доступно объяснил проблему, жду ваших вопросов/предложений по решению)
PS. Вот, например, есть вариант в методе firePropertyChangeEvent() определять имя вызывающего метода путем анализа стека. Но это совсем не красиво, кмк.
Еще можно использовать compile-time аннотации, чтобы компилятор дописывал ид события сам. Это труъ?

Spring AOP или схожее может помочь в данной ситуации. Повесить перехватчики на все set* методы в конкретном пакете. Правда не знаю как быть с ситуацией когда переприсваивается старое значение.

sargeman
()
Ответ на: комментарий от sargeman

человек велосипедит Property event model. Зачем ему Spring? А?

anonymous
()

m_str_prop

Дальше не читал

slyjoeh ★★★
()

Про анализ стека. Это не только некрасиво, это ещё и очень медленно и может поломаться при определённых настройках JVM.

Я думаю, вам нужна кодогенерация:

public abstract class DummyBean extends BaseBean {
  public abstract String getStringProp();
  public abstract void setStringProp(String stringProp);
}

DummyBean bean = BeanCreator.create(DummyBean.class);

Для этого класса генерируется класс-наследник, объект которого возвращается из метода create. В реализации геттеров-сеттеров можно делать всё, что душе угодно. Простой способ — сделать через java.lang.reflect.Proxy, он будет работать через рефлекшн, но скорее всего достаточно быстро. Если вдруг скорости не хватит, можно будет переделать на генерацию байткода, там точно хватит.

Legioner ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.