JavaBeans и самоанализ - испорчены логические и проиндексированные свойства? - PullRequest
8 голосов
/ 17 января 2011

Бывший мой коллега начал полчаса назад дискуссию о JavaBeans и о том, почему они не работают так, как он хочет в JSF. Частный случай касается булевых свойств.

* 1 * 1004. Для логического свойства с именем isUrl Eclipse генерирует это

private boolean isUrl;
public boolean isUrl() {..}
public boolean setUrl(boolean url) {..}

Но это не работает в JSF. Он заставил это работать, добавив public boolean getIsUrl() Реализация может быть ошибочной, поэтому давайте удостоверимся, кто прав, используя API самоанализа .:

BeanInfo info = Introspector.getBeanInfo(ClassTest.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
      System.out.println(pd.getName() + ": " + pd.getReadMethod() + 
       " : " + pd.getWriteMethod());
}

Для приведенного выше кода это печатает оба метода - т.е. Eclipse прав, JSF неправильный. Но это показалось мне подозрительным, поскольку в спецификации ничего не упоминается о двойном "is".

Но, просматривая спецификацию, я увидел то, что никогда не использовал - так называемые индексированные свойства. Вы можете иметь private String[] bar, а затем public String getBar(int idx). Итак:

2 . Я попробовал это с Introspector, и он не нашел метод чтения для bar. Результат из приведенного выше кода был: bar: null : null. Поэтому я пришел к мысли - теперь интроспектор не соответствует спецификации. Возможно, это не последовало в предыдущем случае, и в конечном итоге JSF прав. Фактически, индексированные свойства могут создать два метода чтения для данного свойства. И это невозможно с классом PropertyDescriptor API самоанализа.

К чему это нас ведет - у нас возможно сломанный API, который не соответствует спецификации. Что приводит к другим реализациям спецификации (JSF, очевидно, использует пользовательскую). Что приводит к дальнейшему недопониманию и путанице.

Идентификатор чего-то, что меня беспокоило - в спецификации JavaBeans они называют соглашения об именах для методов "шаблоны проектирования". Это звучит неправильно для меня.

Итак, теперь на вопросы:

  1. ясно, спецификация JavaBeans
  2. правильный API для самоанализа
  3. - это новая спецификация JavaBeans, необходимая, по крайней мере, для пояснения поведения логических значений (это до некоторой степени субъективно)

Обновление. похоже, что использование JSF bean.isUrl, а не bean.url. Что имеет смысл не работать с аксессором isUrl().

P.S. JDK 1.6.0_20, JSF 1.2, MyFaces

Ответы [ 2 ]

4 голосов
/ 17 января 2011

Свойства Java Bean определяются методами, а не полями. По этой причине класс PropertyDescriptor имеет методы getReadMethod() и getWriteMethod(), но методов getField() нет.

Лично я думаю, что ваш коллега использует плохую практику.

а) is - глагол. Поля не должны быть названы в честь глаголов.
б) хотя это и не требуется, хорошей практикой является именование поля как свойства, что позволяет писать код следующим образом:

PropertyDescriptor pd; // let's assume this is set
Method referenceMethod = pd.getReadMethod() == null
  // at least one of these is not null
  ? pd.getWriteMethod() : pd.getReadMethod(); 
Field underLyingField = referenceMethod
                          .getDeclaringClass()
                          .getDeclaredField(pd.getName());

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

например. Я использую код, подобный приведенному выше, чтобы проверить, есть ли в поле аннотации


Об индексированных свойствах:

Вы можете использовать синтаксис индекса для свойств массива или списка (или карты), но только если они определены как стандартные свойства bean.

Итак, если у вас есть такая собственность:

private String[] bar;
public String[] getBar(){
    return bar;
}
public void setBar(String[] bar){
    this.bar = bar;
}

или как это:

private List<String> bar;
public List<String> getBar(){
    return bar;
}
public void setBar(List<String> bar){
    this.bar = bar;
}

вы можете получить доступ к первому члену с выражением ${bar[0]}

И с таким свойством карты:

private Map<String, String> bar;
public Map<String, String> getBar(){
    return bar;
}
public void setBar(Map<String, String> bar){
    this.bar = bar;
}

Вы можете получить доступ к значению, сопоставленному с "baz" следующим образом ${bar['baz']}.

Эта функциональность основана на стандартной функциональности bean-компонентов, поэтому для нее требуются обычные методы получения / установки.

2 голосов
/ 17 января 2011

Как упоминал @Peter Lawrey, имя поля не имеет значения, если речь идет о JavaBeans. Он даже не должен существовать, или вы можете дать ему глупое имя, например, с префиксом m_.

Вы не предоставили подходящих методов чтения или записи для свойства bar в целом, поэтому они не будут отображаться. Вы не можете синтезировать Method в существующий класс во время выполнения. Я полагаю, что индексированные свойства были более поздней редакцией, хотя не было @since очевидного, поэтому они не используются java.beans интерфейсами.

У меня нет спецификации JSF (и она будет за стеной юриста jcp.org), поэтому не знаю, на что она претендует. Он может указывать что-то отличное от спецификации JavaBeans [вероятный], или вы можете использовать реализацию с ошибками [я думаю, также вероятный].

«Шаблон дизайна» - это просто фраза. Как в шаблоне, который встречается в нашем дизайне. Это не шаблон проектирования, как в GoF.

...