java conditional-compilation

Compilación condicional de Java: ¿cómo evitar que se compilen los fragmentos de código?



conditional-compilation (7)

El script Ant que se presenta a continuación brinda un truco agradable y limpio.

enlace: https://weblogs.java.net/blog/schaefa/archive/2005/01/how_to_do_condi.html

por ejemplo,

//[ifdef] public byte[] getBytes(String parameterName) throws SQLException { ... } //[enddef]

con script Ant

<filterset begintoken="//[" endtoken="]"> <filter token="ifdef" value="${ifdef.token}"/> <filter token="enddef" value="${enddef.token}"/> </filterset>

por favor vaya al enlace de arriba para más detalles.

Mi proyecto requiere Java 1.6 para compilación y ejecución. Ahora tengo el requisito de hacerlo funcionar con Java 1.5 (desde el lado de marketing). Quiero reemplazar el cuerpo del método (el tipo de retorno y los argumentos siguen siendo los mismos) para hacerlo compilar con Java 1.5 sin errores.

Detalles: Tengo una clase de utilidad llamada OS que encapsula todas las cosas específicas del sistema operativo. Tiene un método

public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... }

para abrir archivos como hacer doble clic ( start el comando de Windows o open comando Mac OS X equivalente). Como no se puede compilar con Java 1.5, quiero excluirlo durante la compilación y reemplazarlo por otro método que llame a run32dll para Windows o open para Mac OS X usando Runtime.exec .

Pregunta: ¿Cómo puedo hacer eso? ¿Pueden las anotaciones ayudar aquí?

Nota: Yo uso hormiga, y puedo hacer dos archivos java OS4J5.java y OS4J6.java que contendrán la clase OS con el código deseado para Java 1.5 y 1.6 y copiar uno de ellos a OS.java antes de compilar (o un feo manera - reemplace el contenido de OS.java condicionalmente dependiendo de la versión de Java) pero no quiero hacer eso, si hay otra manera.

Elaborando más: en CI podría usar ifdef, ifndef , en Python no hay compilación y podría verificar una característica usando hasattr o algo más, en Common Lisp podría usar la función #+feature . ¿Hay algo similar para Java?

Encontré esta publicación pero no parece ser útil.

Cualquier ayuda es muy apreciada. kh.


En java 9 es posible crear archivos jar de liberación múltiple. Esencialmente significa que usted hace múltiples versiones del mismo archivo java.

Cuando los compila, compila cada versión del archivo java con la versión jdk requerida. A continuación, debe empaquetarlos en una estructura que se vea así:

+ com + mypackage + Main.class + Utils.class + META-INF + versions + 9 + com + mypackage + Utils.class

En el ejemplo anterior, la parte principal del código se compila en java 8, pero para java 9 hay una versión adicional (pero diferente) de la clase Utils .

Cuando ejecuta este código en java 8 JVM, ni siquiera verifica las clases en la carpeta META-INF. Pero en java 9 lo hará, y encontrará y usará la versión más reciente de la clase.


No soy un gran experto en Java, pero parece que la compilación condicional en Java es compatible y fácil de hacer. Por favor lee:

http://www.javapractices.com/topic/TopicAction.do?Id=64

Citando la esencia:

La práctica de compilación condicional se utiliza para eliminar opcionalmente trozos de código de la versión compilada de una clase. Utiliza el hecho de que los compiladores ignorarán cualquier rama de código inalcanzable. Para implementar la compilación condicional,

  • define un valor booleano final estático como miembro no privado de alguna clase
  • código de lugar que debe compilarse condicionalmente en un bloque if que evalúa el valor booleano
  • establecer el valor de booleano en falso para hacer que el compilador ignore el bloque if; de lo contrario, mantenga su valor como verdadero

Por supuesto, esto nos permite "compilar" trozos de código dentro de cualquier método. Para eliminar miembros de la clase, métodos o incluso clases enteras (tal vez dejando solo un talón) aún necesitarías un preprocesador.


No, no hay soporte para la compilación condicional en Java.

El plan habitual es ocultar los bits específicos del sistema operativo de su aplicación detrás de una Interface y luego detectar el tipo de sistema operativo en tiempo de ejecución y cargar la implementación utilizando Class.forName(String) .

En su caso, no hay ninguna razón por la que no pueda compilar ambos OS* (y de hecho toda su aplicación) usando Java 1.6 con -source 1.5 -target 1.5 luego en un método de fábrica para obtener clases de OS (que ahora sería una interfaz) detecta que la clase java.awt.Desktop está disponible y carga la versión correcta.

Algo como:

public interface OS { void openFile(java.io.File file) throws java.io.IOException; } public class OSFactory { public static OS create(){ try{ Class.forName("java.awt.Desktop"); return new OSJ6(); }catch(Exception e){ //fall back return new OSJ5(); } } }


Ocultar las dos clases de implementación detrás de una interfaz propuesta por Gareth es probablemente la mejor manera de hacerlo.

Dicho esto, puede introducir un tipo de compilación condicional utilizando la tarea de reemplazo en los scripts de compilación de ant. El truco consiste en utilizar comentarios en su código que se abren / cierran mediante un reemplazo de texto justo antes de compilar la fuente, como:

/*{{ Block visible when compiling for Java 6: IFDEF6 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5: IFDEF5 // open the file using alternative methods ... /*}} end of Java 5 code. */

ahora en ant, cuando compile para Java 6, reemplace "IFDEF6" por "* /", dando:

/*{{ Block visible when compiling for Java 6: */ public static void openFile(java.io.File file) throws java.io.IOException { // open the file using java.awt.Desktop ... /*}} end of Java 6 code. */ /*{{ Block visible when compiling for Java 5, IFDEF5 public static void openFile(java.io.File file) throws java.io.IOException { // open the file using alternative methods ... /*}} end of Java 5 code. */

y al compilar para Java 5, reemplace "IFDEF5". Tenga en cuenta que debe tener cuidado de usar // comments dentro de los bloques /*{{ , /*}} .


Puede hacer las llamadas usando reflexión y compilar el código con Java 5.

p.ej

Class clazz = Class.forName("java.package.ClassNotFoundInJavav5"); Method method = clazz.getMethod("methodNotFoundInJava5", Class1.class); method.invoke(args1);

Puede capturar cualquier excepción y recurrir a algo que funciona en Java 5.