Per quel che vale, la maggior parte dei linguaggi di scripting (come Perl) e non statici in fase di compilazione (come Pick) supportano conversioni di oggetti dinamiche di run-time automatiche (relativamente arbitrarie). Ciò PU essere realizzato anche in Java senza perdere la sicurezza dei tipi e le cose buone che i linguaggi tipizzati staticamente forniscono SENZA gli effetti collaterali negativi di alcuni degli altri linguaggi che fanno cose malvagie con il casting dinamico. Un esempio di Perl che fa una matematica discutibile:
print ++($foo = '99'); # prints '100'
print ++($foo = 'a0'); # prints 'a1'
In Java, questo è meglio realizzato (IMHO) utilizzando un metodo che chiamo "cross-casting". Con il cross-casting, la reflection viene utilizzata in una cache con caricamento lento di costruttori e metodi che vengono scoperti dinamicamente tramite il seguente metodo statico:
Object fromString (String value, Class targetClass)
Sfortunatamente, nessun metodo Java integrato come Class.cast () lo farà per String in BigDecimal o String in Integer o qualsiasi altra conversione in cui non esiste una gerarchia di classi di supporto. Da parte mia, il punto è fornire un modo completamente dinamico per raggiungere questo obiettivo - per il quale non credo che il riferimento precedente sia l'approccio giusto - dovendo codificare ogni conversione. In poche parole, l'implementazione è solo per eseguire il cast da stringa se è legale / possibile.
Quindi la soluzione è una semplice riflessione alla ricerca di membri pubblici di:
STRING_CLASS_ARRAY = (nuova classe [] {String.class});
a) Membro membro = targetClass.getMethod (method.getName (), STRING_CLASS_ARRAY); b) Membro membro = targetClass.getConstructor (STRING_CLASS_ARRAY);
Scoprirai che tutte le primitive (Integer, Long, ecc.) E tutte le basi (BigInteger, BigDecimal, ecc.) E persino java.regex.Pattern sono tutte coperte da questo approccio. L'ho usato con notevole successo su progetti di produzione in cui è presente un'enorme quantità di input di valori String arbitrari in cui era necessario un controllo più rigoroso. In questo approccio, se non esiste un metodo o quando il metodo viene invocato viene generata un'eccezione (perché è un valore non valido come un input non numerico per un BigDecimal o RegEx illegale per un Pattern), che fornisce il controllo la logica intrinseca della classe di destinazione.
Ci sono alcuni aspetti negativi in questo:
1) Devi capire bene la riflessione (questo è un po 'complicato e non per i principianti). 2) Alcune delle classi Java e in effetti le librerie di terze parti (sorpresa) non sono codificate correttamente. Cioè, ci sono metodi che accettano un singolo argomento stringa come input e restituiscono un'istanza della classe di destinazione ma non è quello che pensi ... Considera la classe Integer:
static Integer getInteger(String nm)
Determines the integer value of the system property with the specified name.
Il metodo sopra non ha davvero nulla a che fare con gli interi come oggetti che avvolgono le primitive int. Reflection lo troverà come un possibile candidato per la creazione di un numero intero da una stringa in modo errato rispetto ai membri di decodifica, valore e costruttore, che sono tutti adatti per la maggior parte delle conversioni arbitrarie di stringhe in cui non si ha davvero il controllo sui dati di input ma si desidera solo farlo sapere se è possibile un numero intero.
Per rimediare a quanto sopra, la ricerca di metodi che generano eccezioni è un buon inizio perché valori di input non validi che creano istanze di tali oggetti dovrebbero generare un'eccezione. Sfortunatamente, le implementazioni variano a seconda che le eccezioni siano dichiarate come selezionate o meno. Integer.valueOf (String) genera un'eccezione NumberFormatException verificata, ad esempio, ma le eccezioni Pattern.compile () non vengono trovate durante le ricerche di riflessione. Ancora una volta, non un fallimento di questo approccio dinamico "cross-casting", penso tanto come un'implementazione molto non standard per le dichiarazioni di eccezioni nei metodi di creazione di oggetti.
Se qualcuno desidera maggiori dettagli su come è stato implementato quanto sopra, fammelo sapere ma penso che questa soluzione sia molto più flessibile / estensibile e con meno codice senza perdere le parti buone della sicurezza dei tipi. Ovviamente è sempre meglio "conoscere i tuoi dati" ma, come molti di noi scoprono, a volte siamo solo destinatari di contenuti non gestiti e dobbiamo fare del nostro meglio per usarli correttamente.
Saluti.