2011-01-16 6 views
7

Un mio ex collega ha iniziato una discussione mezz'ora fa su JavaBeans e sul perché non ha funzionato nel modo in cui lo desidera in JSF. Il caso particolare riguarda le proprietà booleane.JavaBeans e introspezione: incasinato su proprietà booleane e indicizzate?

. Per una proprietà booleana denominata isUrl Eclipse genera questo

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

Ma questo non funziona in JSF. Egli ha reso il lavoro con l'aggiunta di public boolean getIsUrl() L'implementazione potrebbe essere buggy, quindi cerchiamo di fare in modo chi ha ragione, utilizzando l'API di introspezione .:

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

Per il codice di cui sopra, viene stampato entrambi i metodi - vale a dire Eclipse è giusto, JSF è sbagliato. Ma mi sembrava sospetto, dal momento che lo the specification non menziona nulla sul doppio "è".

Ma guardando le specifiche, ho visto qualcosa che non ho mai usato, le cosiddette proprietà indicizzate. È possibile avere private String[] bar e quindi public String getBar(int idx). Quindi:

. L'ho provato con lo Introspector e non ho trovato un metodo di lettura per barra. Il risultato del codice precedente era: bar: null : null. Così sono arrivato a pensare - ora l'introspettore non segue le specifiche. Forse non l'ha seguito nel caso precedente, e alla fine, JSF ha ragione. In effetti, le proprietà indicizzate possono essere create in modo tale che vi siano due metodi di lettura per una determinata proprietà. E questo non è possibile con la classe PropertyDescriptor dell'API di introspezione.

A cosa ci conduce? Un'API probabilmente non funzionante non conforme alle specifiche. Il che porta ad altre implementazioni delle specifiche (ovviamente JSF usa uno personalizzato). Il che porta a ulteriori equivoci e confusioni.

Un sidenote per qualcosa che mi ha infastidito - nelle specifiche JavaBeans chiamano le convenzioni di denominazione per i metodi "schemi di progettazione". Mi sembra sbagliato.

Così, ora sulle domande:

  1. è il JavaBeans spec chiaro
  2. è l'API di introspezione corretta
  3. è una specifica nuovi JavaBeans necessario, almeno per chiarire il comportamento di booleani (che è soggettiva in misura)

Aggiornamento. sembra che l'utilizzo di JSF sia bean.isUrl piuttosto che bean.url. Il che fa sì che i perfetti non lavorino con l'accessorio isUrl().

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

+0

forse qualcosa come le proprietà di C# tornerà utile. – Bozho

+0

Dopo aver letto il codice introspector, isXxxx dovrebbe funzionare. Il nome del campo utilizzato non ha importanza. Hai provato Java 6 aggiornamento 23? –

risposta

2

Come menzionato da @Peter Lawrey, il nome del campo è irrilevante per quanto riguarda JavaBeans. Non è nemmeno necessario esistere, o puoi dargli un nome stupido come il prefisso con m_.

Non è stato fornito un metodo di lettura o scrittura adatto per la proprietà bar nel suo insieme, quindi non verranno visualizzati. Non è possibile sintetizzare un Method in una classe esistente in fase di runtime.Credo che le proprietà indicizzate fossero in ritardo, anche se non c'è un @since apparente, quindi non sono utilizzate dalle interfacce java.beans.

Non ho le specifiche JSF (e sarà dietro il muro dell'avvocato di jcp.org), quindi non so cosa pretende. Potrebbe specificare qualcosa di diverso rispetto alla specifica JavaBeans [probabile], oppure potresti usare un'implementazione con bug [credo sia anche probabile].

"Design pattern" è solo una frase. Come in un modello che si verifica nel nostro design. Non è Design Pattern come in GoF.

+0

+1. Sì, la "irrilevanza" del nome del campo è qualcosa a cui siamo arrivati ​​nella discussione, e questo spiega il comportamento di Eclipse e dell'Introspector. Eclipse è solo intelligente. Riguardo ai modelli di design - Sono d'accordo che è solo una frase, ma è quella che ha ricevuto un significato molto specifico - quello di GoF. Non che non possa significare nient'altro, ma è solo strano. – Bozho

4

Le proprietà Java Bean sono definite dai metodi, non dai campi. Per questo motivo la classe PropertyDescriptor ha i metodi getReadMethod() e getWriteMethod(), ma non i metodi getField().

Personalmente, penso che il tuo collega stia usando una cattiva pratica.

a) is è un verbo. I campi non dovrebbero essere il nome dei verbi.
b), mentre non è richiesto, buona pratica è quella di assegnare un nome al campo, come la proprietà, che permette di scrivere codice come questo:

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

Anche se questo codice non è standardizzato, viene seguenti convenzioni vi consentirà di entrare molto maneggevole. Se non segui convenzioni come questa, non hai modo di associare un campo con una proprietà (che è intenzionale, lo so).

ad es. Io uso il codice come sopra per verificare se il campo ha le annotazioni


Circa proprietà indicizzate:

È possibile utilizzare la sintassi indice su array o proprietà lista (o mappa), ma solo se sono definiti come proprietà dei bean standard.

Quindi, se si dispone di una proprietà come questa:

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

o come questo:

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

è possibile accedere il primo membro con l'espressione ${bar[0]}

E con una mappa property così:

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

È possibile accedere al valore mappato a "baz" come questo ${bar['baz']}.

Questa funzionalità si basa sulla funzionalità dei bean standard, pertanto richiede getter/setter regolari.

+0

(+1).generalmente, sono d'accordo che una proprietà booleana non dovrebbe includere 'is', ma per me ha senso se il nome del campo è un nome, piuttosto che un aggettivo. – Bozho

+1

@Bozho divertente, ho pensato che fosse una convenzione altamente accettata che i nomi dei campi non dovessero essere verbi, ma non riesco a trovare nulla che supporti questa affermazione. Tutti dicono che un nome di metodo dovrebbe essere un verbo, e per me questo implica che un campo non dovrebbe, ma nessuno lo dice esplicitamente (né di Sun, Wikipedia, Joshua Bloch) –