2010-03-15 14 views
8

Voglio impacchettare un pezzo di codice che assolutamente deve essere eseguito su Java 1.5. C'è una parte del codice in cui il programma può essere "migliorato" se la VM è una VM di 1,6.Java: il modo più semplice per impacchettare entrambi i codici Java 1.5 e 1.6

In sostanza è questo metodo:

private long[] findDeadlockedThreads() { 
    // JDK 1.5 only supports the findMonitorDeadlockedThreads() 
    // method, so you need to comment out the following three lines 
    if (mbean.isSynchronizerUsageSupported()) 
     return mbean.findDeadlockedThreads(); 
    else 
     return mbean.findMonitorDeadlockedThreads(); 
    } 

Quale sarebbe modo più semplice per avere questo compilare su 1,5 eppure fare il metodo 1.6 chiamate quando il 1.6?

In passato ho fatto qualcosa di simile compilando una classe 1.6 unica che avrei assemblato con la mia app e istanziato usando un ClassLoader quando su 1.6 (perché una JVM 1.6 sta perfettamente bene combinando le classi 0x32 e 0x31), ma Penso che sia un po 'eccessivo (e un po' doloroso perché durante il processo di compilazione devi creare sia i file 0x31 che 0x32 .class).

Come devo andare se volessi compilare il metodo sopra su 1.5? Forse utilizzando la riflessione, ma allora come (io non sono a conoscenza a tutti, con la riflessione)

Nota: se siete curiosi, il metodo di cui sopra viene da questo articolo: http://www.javaspecialists.eu/archive/Issue130.html

(ma io non voglio "commenta le tre righe" come nell'articolo, voglio che compili e funzioni sia su 1.5 che su 1.6)

risposta

3

Non puoi compilarlo a 1.5, ma puoi compilare su 1.6 con l'opzione di destinazione impostata su 1.5 (questo produrrebbe un codice byte per 1.5) e nel codice usando la riflessione per scoprire se il metodo è disponibile.

Questo codice cerca il metodo: mbean.getClass(). GetMethod ("findDeadlockedThreads", new Class [0]); Il problema è che genera una NoSuchMethodException se il metodo non è presente invece di restituire semplicemente null o qualcosa di simile. Ciò significa che è necessario il codice come questo:

try 
{ 
    mbean.getClass().getMethod("findDeadlockedThreads", new Class<?>[0]); 
    return mbean.findDeadlockedThreads(); 
} 
catch(NoSuchMethodException ex) 
{ 
    return mbean.findMonitorDeadlockedThreads(); 
} 

Questo non è molto bello, perché utilizza un'eccezione per prendere una decisione. Probabilmente non è molto veloce. Un'alternativa è usare getMethods invece e scorrere l'elenco restituito se il tuo metodo è disponibile. Anche questo non è molto veloce.

MODIFICA: Christopher Oezbek suggerisce nei commenti di effettuare il controllo dell'esistenza del metodo solo una volta e di salvare il risultato per evitare il sovraccarico per il blocco Try-catch. È giusto e una buona soluzione. matt b avverte che l'opzione target del Java-Compiler non controlla, se le classi e i metodi utilizzati sono disponibili in Java 1.5. Esatto (e altrimenti non funzionerebbe, perché si vuole compilare con un metodo 1.6) e ciò significa che il programma dovrebbe essere testato con attenzione in un 1.5-VM, per evitare questo problema. Grazie per i vostri commenti entrambi.

+0

@Mnementh: ok, ma poi che cosa sarebbe il codice riflessione assomigliare ? – SyntaxT3rr0r

+0

Ho modificato la mia risposta per includere il reflection-code. – Mnementh

+0

@Mnementh: +1 ottimo ... Proverò a configurarlo questo pomeriggio :) – SyntaxT3rr0r

2

Compila per 1.5.

Nel codice utilizzare la riflessione. È possibile ottenere l'oggetto Method dall'interfaccia di classe; ha un metodo invoke che prende l'istanza mbean come parametro. Qualcosa del genere:

Classe c = mbean.getClass(); // può anche fare YourClass.class per ottenere questo

Metodo m = c.GetMethod ("findMonitorDeadLockedThreads"); // o qualsiasi altro metodo (parametri il metodo sono specificati con classe ... secondo parametro di getMethod)

m.invoke (MBean) // invoca il metodo con il vostro esempio

Naturalmente don devo farlo ogni volta; imposta i riferimenti al metodo in un costruttore e poi invoca quello giusto su richiesta.

+0

@danpaq: è un caso semplice perché non ci sono parametri da passare al metodo. Quindi da Mnementh e dalla tua risposta prendo la riflessione è la strada da percorrere ... Quindi proverò ciò che hai suggerito qui. – SyntaxT3rr0r

+0

@WizardOfOdds: se ritieni che questo suggerimento sia valido, ti preghiamo di revocarlo. –

1

Maven ti permette di farlo abbastanza facilmente con i profili. L'idea dietro i profili è che vuoi costruire le due versioni differenti di qualcosa basandoti su alcuni criteri. In questo esempio specifico, è possibile definire un profilo jdk15 e un profilo , specificare quale versione JDK compilare con ciascuno e dirgli di includere una copia della classe nel profilo jdk15 e l'altra in jdk16.

Per iniziare, vedi:

http://unserializableone.blogspot.com/2008/09/compile-and-test-with-different-jdk.html

Questo descrive come fare la parte diversa versione del JDK del problema.

per gestire la seconda parte del problema, utilizzando una definizione diversa della classe seconda della versione JDK, vedere questo:

Maven - Include Different Files at Build Time

+0

Scusa, spero che sia d'aiuto ... Non ho un momento libero in questo momento per mostrarti l'intero script di costruzione di maven. –

+0

Giusto per essere sicuro di aver capito quello che hai detto correttamente: ho bisogno di impacchettare e spedire un unico * .jar * funzionante sia su 1.5 che 1.6 che usa 1.6 caratteristiche quando su 1.6, posso farlo con i profili di Mave? – SyntaxT3rr0r

+0

@WizardOfOdds: Sì, questo è quello che ho cercato di descrivere prima. Ho rivisto la mia risposta per avere link che descrivono come farlo meglio di quanto potrei descrivere qui. –

Problemi correlati