2011-01-16 2 views
7

Ein ehemaliger Kollege von mir begann vor einer halben Stunde eine Diskussion über JavaBeans, und warum sie nicht so funktionierten, wie er es in JSF will. Im speziellen Fall geht es um boolesche Eigenschaften.JavaBeans und Introspektion - versaut auf booleschen und indizierten Eigenschaften?

. Für eine Boolesche Eigenschaft namens isUrl Eclipse-generiert diese

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

Aber in JSF nicht funktioniert. Er machte es Arbeit durch Hinzufügen public boolean getIsUrl() Die Umsetzung könnte fehlerhaft sein, so lassen Sie uns sicherstellen, wer Recht hat, durch die Selbstbeobachtung API .:

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

Für den obigen Code, diese beiden Methoden druckt - dh Eclipse ist richtig, JSF ist falsch. Aber das klang mir verdächtig, da the specification nichts über das doppelte "ist" erwähnt.

Aber während ich durch die Spezifikation schaute, sah ich etwas, das ich nie benutzt habe - die so genannten indizierten Eigenschaften. Sie können private String[] bar und dann public String getBar(int idx) haben. Also:

. Ich habe das mit der Introspector versucht, und es hat keine Lese-Methode für bar gefunden. Das Ergebnis aus dem obigen Code war: bar: null : null. So kam ich zu denken - jetzt folgt der Introspektor nicht der Spezifikation. Vielleicht ist es ihm im vorhergehenden Fall nicht gefolgt, und schließlich hat JSF Recht. Tatsächlich können indexierte Eigenschaften so aussehen, dass es zwei Lesemethoden für eine bestimmte Eigenschaft gibt. Und das ist mit der Klasse PropertyDescriptor der Introspektions-API nicht möglich.

Was führt uns dazu - wir haben eine möglicherweise kaputte API, die nicht der Spezifikation entspricht. Das führt zu anderen Implementierungen der Spezifikation (JSF verwendet offensichtlich eine benutzerdefinierte). Das führt zu weiteren Missverständnissen und Verwirrungen.

Eine Randnotiz für etwas, das mich gestört hat - in der JavaBeans-Spezifikation nennen sie die Namenskonventionen für die Methoden "Design Patterns". Das klingt falsch für mich.

So, nun auf die Fragen:

  1. die Java Beans-Spezifikation klar
  2. ist die Selbstbeobachtung API korrekt
  3. wird eine neue Java Beans-Spezifikation erforderlich, zumindest ist das Verhalten von booleans zu klären (das ist subjektiv bis zu einem gewissen Grad)

Update. Es scheint, dass die JSF-Verwendung bean.isUrl eher als bean.url ist. Was macht Sinn, nicht mit isUrl() Accessor zu arbeiten.

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

+0

vielleicht wird so etwas wie C# -Eigenschaften nützlich sein. – Bozho

+0

Nach dem Lesen des Introspector-Codes sollte isXxxx funktionieren. Der verwendete Feldname spielt keine Rolle. Hast du Java 6 Update 23 ausprobiert? –

Antwort

2

Wie von @Peter Lawrey erwähnt, ist der Name des Feldes in Bezug auf JavaBeans irrelevant. Es muss nicht einmal existieren, oder du kannst ihm einen dummen Namen geben, wie zum Beispiel m_.

Sie haben keine geeigneten Lese- oder Schreibmethoden für die bar-Eigenschaft als Ganzes bereitgestellt, sodass diese nicht angezeigt werden. Sie können eine Method zu einer vorhandenen Klasse zur Laufzeit nicht synthetisieren.Ich glaube, indexierte Eigenschaften waren eine späte Ausgabe, obwohl es keine @since offensichtlich, so dass sie nicht von java.beans Schnittstellen verwendet werden.

Ich habe nicht die JSF-Spezifikation (und es wird hinter der jcp.org Anwalt Wand), so weiß nicht, was es behauptet. Es kann etwas anderes als die JavaBeans-Spezifikation [wahrscheinlich] angeben, oder Sie verwenden möglicherweise eine Implementierung mit Fehlern [ich denke auch wahrscheinlich].

"Design-Muster" ist nur ein Satz. Wie in einem Muster, das in unserem Design vorkommt. Es ist kein Design Pattern wie in GoF.

+0

+1. Ja, die "Irrelevanz" des Feldnamens ist etwas, zu dem wir in der Diskussion gekommen sind, und dies erklärt das Verhalten der Finsternis und des Introspektors. Eclipse ist einfach clever. Über Design Patterns - ich stimme zu, es ist nur eine Phrase, aber es hat eine sehr spezifische Bedeutung erhalten - die von GoF gegeben. Nicht, dass es nichts anderes bedeuten kann, aber es ist nur komisch. – Bozho

4

Java Bean-Eigenschaften werden durch Methoden und nicht durch Felder definiert. Aus diesem Grund hat die PropertyDescriptor Klasse getReadMethod() und getWriteMethod() Methoden, aber keine getField() Methoden.

Persönlich denke ich, dass Ihr Kollege eine schlechte Praxis verwendet.

a) is ist ein Verb. Felder sollten nicht nach Verben benannt werden.
b), während es nicht erforderlich ist, ist eine gute Praxis, das Feld wie die Eigenschaft zu nennen, die Sie so schreiben Code können:

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()); 

Während dieser Code nicht standardisiert ist, kommen in ihm folgenden Konventionen und sehr praktisch. Wenn Sie Konventionen wie diese nicht befolgen, haben Sie keine Möglichkeit, ein Feld mit einer Eigenschaft zu verbinden (was beabsichtigt ist, weiß ich).

z.B. Ich verwende Code wie oben zu überprüfen, ob das Feld Anmerkungen hat


über indizierte Eigenschaften:

Sie können den Index Syntax auf Array oder eine Liste (oder Karte) Eigenschaften, aber nur, wenn sie definiert sind als Standard-Bean-Eigenschaften.

Also, wenn Sie eine Eigenschaft wie folgt aus:

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

oder so:

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

Sie das erste Element mit dem Ausdruck zugreifen können ${bar[0]}

Und mit einer Karte Immobilien so:

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

Sie können auf den auf "baz" abgebildeten Wert wie diesen ${bar['baz']} zugreifen.

Diese Funktionalität baut auf der Funktionalität von Standard-Beans auf, daher sind regelmäßige Getter/Setter erforderlich.

+0

(+1).Im Allgemeinen stimme ich zu, dass eine boolesche Eigenschaft nicht "is" enthalten sollte, aber für mich macht es Sinn, wenn der Feldname ein Substantiv ist und kein Adjektiv. – Bozho

+1

@Bozho lustig, ich dachte, es war eine hoch akzeptierte Konvention, dass Feldnamen keine Verben sein sollten, aber ich kann nichts finden, um diese Behauptung zu untermauern. Jeder sagt, dass ein Methodenname ein Verb sein sollte, und für mich bedeutet das, dass ein Feld nicht sollte, aber niemand so explizit sagt (weder von Sun noch von Wikipedia, von Joshua Bloch). –