2009-06-22 12 views
10

Java Reflection fornisce un meccanismo per l'introspezione di un oggetto in fase di esecuzione. Nessun ripensamento, questa è una grande funzionalità, ma rompe tutte le convenzioni di Refactoring!Java Reflection e il dolore nel Refactoring

Non esiste un modo semplice (diverso da File Search) anche nei moderni IDE per sapere a quale attributo viene fatto riferimento e dove. Questo rende i Refactoring molto più complessi (noiosi!) E soggetti a errori.

Per essere sinceri, non è solo il Reflection API; Hibernate mapping files (hbm.xml) e JSP files si riferiscono entrambi agli attributi come String e quando si rifatta il nome dell'attributo, è necessario modificare manualmente tutti questi punti.

Peggio ancora, le modifiche nei file di mapping di Hibernate o nei file JSP causano errori di runtime.

Sono interessato a sapere come altri programmatori gestiscono questo in Java. Ci sono alcuni strumenti? Uso Eclipse/IBM RAD come piattaforma di sviluppo principale. Normalmente utilizziamo un constant per definire l'attributo e usarlo quando possibile ma non è sempre possibile.

Sarei anche interessato a come altri linguaggi gestiscono questo!

+1

IntelliJ ha abbastanza buoni ganci nei file di configurazione JSP, Spring e Hibernate in questi giorni, che sono tutti "refactoring aware". Non sono un utente di Eclipse, ma ho pensato che avesse qualcosa di simile. –

+0

anche netbeans ha alcuni strumenti intelligenti di refactoring (spring, web.xml, ecc.) – dfa

+0

Penso che Eclipse possa refactoring anche sui file Hibernate. –

risposta

7

La riflessione Java causa molti degli stessi problemi con linguaggi digitati dinamicamente come Python e Ruby. In effetti, un modo per pensare alle lingue digitate dinamicamente è che tutto viene chiamato usando la riflessione, e le lingue forniscono solo una sintassi bella e pulita per la riflessione.

E sì, con linguaggi tipizzati dinamicamente (o pesanti usi della riflessione), il refactoring è difficile. Non hai le simpatiche capacità di refactoring di Eclipse. Invece, grep diventa tuo amico.

Dalla mia esperienza, la cosa migliore che puoi fare è costruirti una buona rete di sicurezza dei test unitari. In questo modo, se rompi un codice dinamico durante il refactoring, almeno lo prendi rapidamente quando esegui i test.

Se stai facendo un sacco di codice tipizzato staticamente, sei in grossi guai se non hai una buona base di test unitari. Se stai facendo un sacco di codice digitato dinamicamente (incluso il codice con molta riflessione), non hai alcuna speranza di avere successo senza una buona base di test unitari.

+0

In realtà, il primo IDE che implementava il refactoring era Smalltalk, che è piuttosto dinamico. AFAIK lo strumento di refactoring ha effettuato l'analisi monitorando il codice mentre veniva eseguito (di solito attraverso i test unitari) e osservando quali percorsi sono utilizzati, quali metodi vengono chiamati, ecc. È possibile refactoring il codice dinamico, ma è difficile da implementare e credo questo è il motivo per cui non è ampiamente disponibile in IDE. – gooli

2

Gli IDE moderni hanno la caratteristica che quando si rinomina una classe, cercheranno il nome completo, ad esempio, nei file xml per cercare di rinominare qualsiasi riferimento che si possa avere in essi. Non pensare che risolva il problema - molto spesso non fai assolutamente riferimento ai nomi delle classi.

Inoltre, è per questo che è necessario prestare particolare attenzione e considerazione prima di utilizzarlo nel proprio codice.

Ma questo problema con la riflessione è il motivo per cui le annotazioni stanno diventando più popolari. Il problema si riduce quando si usano le annotazioni.

Ma lasciatemi dire, come giustamente fa notare il post precedente, se non si dispone di una buona rete di sicurezza dei test unitari, qualsiasi tipo di refactoring, indipendentemente dal fatto che si utilizzi molto riflesso o meno, è pericoloso.

+0

In che modo l'annotazione risolve il problema in tali scenari? Puoi fare un esempio? Grazie. – lud0h

+0

Ad esempio, è in termini di persistenza. Se uso le annotazioni per specificare che una classe è persistente, ad esempio, e rinominare quella classe, l'annotazione rimarrà e sarà ancora persistente. Non dovrò andare a trovare tutte le istanze in cui la classe è riferimenti nei file di mapping e cambiare anche quello. –

0

Potrebbe essere interessato l'uso di IntelliJ IDEA, che cercherà anche nomi di classi refactored nei commenti e costanti di stringa.

+0

netbeans (e probabilmente anche altri) – dfa

+1

Eclipse (e presumibilmente netbeans) può farlo anche questo - ma non è ancora garantito il funzionamento, dal momento che vedrà solo nomi di classi pienamente qualificati –

0

Bene, è un'altra opportunità per IDE per vendere costose versioni premium in grado di riconoscere e refactoring nomi di classe utilizzati in specifici file di configurazione.

In alternativa, tali casi ricorrenti possono essere gestiti da una suite di test che esegue il controllo di integrità su tali file, ovvero verifica che esistano tutte le classi e i metodi indicati. Tali sono specifici per un formato di file, ma sono spesso relativamente facili da scrivere e possono quindi essere utilizzati per controllare tutti i file di quel formato.

Ma non esiste una soluzione generale per l'uso diretto, "manuale" dell'API di riflessione, motivo per cui è generalmente scoraggiato.

+0

Il problema non è solo con l'API di Reflection. I file di configurazione come Hibernate o JSP sono vincolati a tempo di compilazione e gli strumenti non li catturano in modo efficace. – lud0h

+0

Poiché questi file hanno una sintassi ben definita, è almeno possibile (e non troppo difficile). –

1

Il refactoring potrebbe essere migliorato introducendo più "letterali" nella lingua. Per esempio. imho. class letterale sono un ottimo modo per garantire la sicurezza in fase di compilazione di alcuni modelli. Tuttavia, la cosa importante da dire qui è che, a volte, voglio perdere la sicurezza in fase di compilazione. Le stringhe sono il modo più semplice ma potente per esprimere un contratto liberamente accoppiato tra due livelli poiché è possibile manipolarli o abbinarli a un'espressione regolare, ecc.

Il vero problema del riflesso è l'uso prolisso dell'API. Il costo maggiore per la flessibilità.

PS

Progetto moneta potrebbe introdurre qualche parte in futuro qualche nuova lingua costrutto per migliorare questa zona.

0

Per inciso, Reflection causa anche problemi se si desidera proteggere il codice tramite l'offuscamento. Gli strumenti di offuscamento tipici ora richiedono di mantenere un elenco di tutti i file che non si vogliono offuscare in modo che la riflessione da tutti i file di configurazione XML funzioni correttamente.

Detto questo, una versione J2EE di Eclipse IDE con plug-in adatti per i principali framework come Hibernate, Spring ecc. Farà un buon lavoro di gestione del refactoring. I test unitari ridurranno il ciclo di test, ma la preoccupazione è che a volte i test delle unità dipendono anche da alcune configurazioni XML che obbligano a utilizzare la reflection. Quindi è possibile interrompere i test unitari insieme al codice durante il refactoring.

0

E per quanto riguarda le classi di taggin, i metodi, i campi che conosci si accede alla riflessione? L'IDE potrebbe avvisarti quando cambi il loro nome.

0

È possibile evitare di scrivere API di riflessione con dp4j.com quando si è al momento della compilazione ciò che si sta cercando.

Informazioni sui mapping xml, sono un problema, ho anche sperimentato con NetBeans Platform e meno con JPA2. La buona notizia è che le annotazioni stanno prendendo il sopravvento e questo offre di nuovo un controllo in fase di compilazione. Non sono sicuro di Hibernate, ma sia JPA che NetBeans (more as of 7) offrono equivalenti di annotazione di mapping xml.

Avevo anche sviluppato SqlWrapper per evitare di utilizzare stringhe con JDBC. Più sofisticata (e complicata) è l'API dei criteri di JPA2.

Problemi correlati