2015-09-08 23 views
10

Il codice seguente è un piccolo esempio che riproduce facilmente il problema. Quindi ho variabile di tipo String, su cui è impostato un valore predefinito. Ho 3 metodi:Introspezione Java - comportamento strano

  • getter
  • setter
  • metodo comodo che converte la stringa booleano

L'introspezione non restituisce il getter come ReadMethod e il setter come il writeMethod. Invece restituisce il metodo isTest() come readMethod. Il setter è vuoto.

Dalla documentazione capisco che se il tipo sarebbe un booleano, il metodo "è" ha precedenza più alta su get, ma il tipo è String, quindi non ha senso cercare anche un "is-xxx " metodo?

public class Test { 
    public class Arguments { 
     private String test = Boolean.toString(true); 

     public boolean isTest() { 
      return Boolean.parseBoolean(test); 
     } 

     public String getTest() { 
      return test; 
     } 

     public void setTest(String test) { 
      this.test = test; 
     } 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) throws IntrospectionException { 
     BeanInfo info = Introspector.getBeanInfo(Arguments.class); 
     System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod()); 
     System.out.println("Setter: " + info.getPropertyDescriptors()[1].getWriteMethod()); 
     PropertyDescriptor descr = new PropertyDescriptor("test", Arguments.class); 
     System.out.println("T"); 
    } 

} 

C'è qualcuno che ha qualche intuizione su questo?

Ulteriori informazioni:

  1. L'ordine non cambia il risultato. Il metodo isTest() è sempre visto come readMethod
  2. Nel caso in cui semplicemente rinomini isTest() a bsTest(), seleziona getter e setter come readMethod e writeMethod. Quindi ha qualcosa a che fare con "is-xxx".
+0

Cosa succede se dichiari il metodo 'isTest' alla fine della classe? Potrebbe essere che sia riconosciuto come booleano perché è la prima occorrenza e quindi il setter non corrisponde al tipo String. –

+0

No, non ha senso, ma a quanto pare è quello che hanno deciso (o è un bug). Non puoi fare molto su questo, tranne fermarti per rappresentare i booleani con le stringhe: D – Dici

+0

Ho aggiunto qualche informazione in più nel testo iniziale. L'ordine non ha effetto sul risultato. – Quirexx

risposta

4

Il risultato che si ottiene è in realtà il risultato previsto, come da JavaBeans specification.

Citando il paragrafo 8.3.1 per semplici proprietà:

Se scopriamo una coppia corrispondente di get<PropertyName> e set<PropertyName> metodi che prendere e restituire lo stesso tipo, quindi consideriamo questi metodi come la definizione di una lettura-scrittura proprietà il cui nome sarà <propertyName>.

Poi, citando il paragrafo 8.3.2 per le proprietà booleane:

Questo metodo is<PropertyName> può essere fornito al posto di un metodo get<PropertyName>, oppure può essere fornito in aggiunta ad un metodo get<PropertyName>.

In entrambi i casi, se il metodo is<PropertyName> è presente per una proprietà booleana, verrà utilizzato il metodo is<PropertyName> per leggere il valore della proprietà.

Dal tuo esempio, l'Introspector rileva sia il metodo isTest e getTest. Poiché lo isTest ha la priorità su getTest, utilizza isTest per determinare il tipo di proprietà test come boolean. Ma poi, l'Introspector si aspetta che il setter abbia la firma void setTest(boolean test) e non la trovi, quindi il metodo setter è null.

Ciò che è importante notare è che Introspector non legge i campi. Utilizza la firma dei metodi getter/setter per determinare quali campi sono presenti e i loro tipi corrispondenti. La firma del metodo isTest specifica per una proprietà denominata test di tipo boolean, quindi, indipendentemente dal tipo effettivo di test, l'Introspector considererà che la classe ha una proprietà boolean test.

Infatti, per tutti gli Introspecter, la proprietà test potrebbe non esistere nemmeno! Puoi convincertene con il seguente codice:

class Test { 

    public class Arguments { 
     public boolean isTest() { 
      return true; 
     } 
    } 

    public static void main(String[] args) throws IntrospectionException { 
     BeanInfo info = Introspector.getBeanInfo(Arguments.class); 
     System.out.println("Getter: " + info.getPropertyDescriptors()[1].getReadMethod()); 
     System.out.println("Name of property: " + info.getPropertyDescriptors()[1].getName()); 
    } 

} 
+0

Sono d'accordo con Tunaki, e se stai facendo qualche metaprogrammazione, puoi forzarla a funzionare come vuoi con alcuni parametri: 'PropertyDescriptor descr = new PropertyDescriptor (" test ", Arguments.class," getTest "," setTest ") ; ' –

+0

Si dice" usa isTest per determinare il tipo di proprietà di test come booleano ", ma il tipo di test è chiaramente definito come String. O sta definendo il tipo come booleano perché il valore di ritorno del metodo è booleano? – Quirexx

+0

@Quirexx Introspector non legge i campi. Utilizza la firma del metodo getter/setter per determinare quali campi sono presenti e i loro tipi corrispondenti. La firma 'isTest' specifica per una proprietà denominata" test "di tipo booleano, indipendentemente dal tipo effettivo di" test " – Tunaki

2

Il membro effettivo è completamente irrilevante per lo Introspector. È possibile, ad esempio, avere un metodo getName() che restituisce solo un valore fisso String e che l'Introspector lo troverà come getter per un membro chiamato "nome". Puoi anche avere un setter se il membro non esiste. Puoi persino fornire un'interfaccia allo Introspector e determinerà le proprietà da esso, anche se non possono esserci membri reali.

In altre parole, le proprietà sono determinate dall'esistenza dei metodi getter e setter e non dalla ricerca effettiva di variabili.