2010-03-15 8 views
8

Quiero empaquetar un código que absolutamente debe ejecutar en Java 1.5. Hay una parte del código donde el programa puede ser "mejorado" si la VM es una máquina virtual de 1.6.Java: forma más fácil de empaquetar código Java 1.5 y 1.6

Básicamente se trata de este método:

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

¿Cuál sería manera más fácil de tener esta compilar de 1,5 y, sin embargo hacer el método 1.6 llama cuando en 1,6?

En el pasado he hecho algo similar al compilar una clase 1.6 única que empacaría con mi aplicación y crear instancias usando un ClassLoader cuando estaba en 1.6 (porque una 1.6 JVM está perfectamente bien mezclando clases 0x32 y 0x31), pero Creo que es un poco exagerado (y un poco doloroso porque durante el proceso de compilación tienes que compilar ambos archivos .class 0x31 y 0x32).

¿Cómo debo ir si quiero compilar el método anterior en 1.5? Tal vez el uso de la reflexión, pero entonces, ¿cómo (no estoy familiarizado en absoluto con la reflexión)

Nota: si usted es curioso, el método anterior proviene de este artículo: http://www.javaspecialists.eu/archive/Issue130.html

(pero yo no quiero "comentar las tres líneas" como en el artículo, quiero que compile y se ejecute en 1.5 y 1.6)

Respuesta

3

No puede compilar esto en 1.5, pero puede compilar en 1.6 con la opción de destino establecida en 1.5 (eso produciría byte-code para 1.5) y en el código usando reflection para descubrir si el método está disponible.

Este código buscaría el método: mbean.getClass(). GetMethod ("findDeadlockedThreads", new Class [0]); El problema es que arroja una NoSuchMethodException si el método no está presente en lugar de simplemente devolver nulo o algo similar. Eso significa, que necesita un código como éste:

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

que no es muy agradable, ya que utiliza una excepción para tomar una decisión. Probablemente no sea muy rápido. Una alternativa es usar getMethods en su lugar e iterar sobre la lista devuelta si su método está disponible. Eso tampoco es muy rápido.

EDIT: Christopher Oezbek sugiere en los comentarios que compruebe la existencia del método solo una vez y guarde el resultado para evitar la sobrecarga del Try-catch-block. Eso es correcto y una buena solución. matt b advierte que la opción de destino del Java-Compiler no se verifica si las clases y métodos utilizados están disponibles en Java 1.5. Eso es correcto (y de lo contrario no funcionaría, porque desea compilar contra un método 1.6) y eso significa que el programa debe probarse cuidadosamente en un 1.5-VM para evitar este problema. Gracias por sus comentarios los dos.

+0

@Mnementh: bien, pero luego lo haría el aspecto código de reflexión como ? – SyntaxT3rr0r

+0

He editado mi respuesta para incluir el código de reflexión. – Mnementh

+0

@Mnementh: +1 genial ... Intentaré configurarlo esta tarde :) – SyntaxT3rr0r

2

Compile for 1.5.

En su código utilice la reflexión. Puede obtener el objeto Método desde la interfaz de Clase; tiene un método de invocación que toma su instancia mbean como parámetro. Algo como esto:

Clase c = mbean.getClass(); // también puede hacer YourClass.class para obtener este

Método m = c.getMethod ("findMonitorDeadLockedThreads"); // o cualquier otro método (parámetros a el método se especifican con clase ... segundo parámetro a getMethod)

m.invoke (mbean) // invoca el método con la instancia

Por supuesto que don tienes que hacer esto cada vez; configure las referencias del Método en un constructor y luego invoque el correcto a pedido.

+0

@danpaq: es un caso simple porque no hay parámetros para pasar al método. Entonces, desde Mnementh y tu respuesta, considero que la reflexión es el camino a seguir ... Así que voy a intentar lo que sugieres aquí. – SyntaxT3rr0r

+0

@WizardOfOdds: si crees que esta sugerencia es valiosa, vuélvela. –

1

Maven le permite hacer esto fácilmente con los perfiles. La idea detrás de los perfiles es que desea construir cosas dos versiones diferentes de algo en función de algunos criterios. En este ejemplo específico, puede definir un jdk15 y un perfil jdk16, especificar con qué versión JDK compilarse, y decirle que incluya una copia de la clase en el perfil jdk15 y la otra en jdk16.

Para empezar, consulte:

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

Esto describe cómo hacer las diferentes versiones JDK parte del problema.

para manejar la segunda parte del problema, utilizando una definición diferente de la clase en función de la versión del JDK, ver esto:

Maven - Include Different Files at Build Time

+0

Lo siento, espero que ayude ... No tengo un momento libre ahora mismo para mostrarte el script completo de construcción maven. –

+0

Solo para asegurarme de que entiendo lo que dijo correctamente: necesito empacar y enviar un * .jar * único que funcione tanto en 1.5 como en 1.6 que usa funciones 1.6 cuando en 1.6, ¿puedo hacer esto con los perfiles de Mave? – SyntaxT3rr0r

+0

@WizardOfOdds: Sí, eso es lo que traté de describir antes. Revisé mi respuesta para tener enlaces que describan cómo hacerlo mejor de lo que podría describir aquí. –

Cuestiones relacionadas