2008-09-19 15 views
10

Cuando solía escribir bibliotecas en C/C++ tuve el hábito de tener un método para devolver la fecha/hora de compilación. Esto siempre fue compilado en la biblioteca, por lo que diferenciaría las compilaciones de la biblioteca. Tengo esta devolviendo un # define en el código:¿Hay alguna manera de definir un valor constante para Java en tiempo de compilación

C++:

#ifdef _BuildDateTime_ 
    char* SomeClass::getBuildDateTime() { 
     return _BuildDateTime_; 
    } 
#else 
    char* SomeClass::getBuildDateTime() { 
     return "Undefined"; 
    } 
#endif 

A continuación, en la compilación que tenían un '-D_BuildDateTime_ = Date' en el script de construcción.

¿Hay alguna manera de lograr esto o algo similar en Java sin tener que recordar editar cualquier archivo manualmente o distribuir cualquier archivo por separado?

Una sugerencia que obtuve de un compañero de trabajo fue obtener el archivo ant para crear un archivo en el classpath y empaquetarlo en el JAR y hacer que lo lea el método.

Algo así como (suponiendo que el archivo creado se llamó 'DateTime.dat'):

// I know Exceptions and proper open/closing 
// of the file are not done. This is just 
// to explain the point! 
String getBuildDateTime() { 
    return new BufferedReader(getClass() 
      .getResourceAsStream("DateTime.dat")).readLine(); 
} 

Para mi mente que es un truco y podría eludirse/roto por alguien que tenga un archivo de nombre similar fuera de la JAR, pero en el classpath.

De todos modos, mi pregunta es si hay alguna manera de inyectar una constante en una clase en tiempo de compilación

EDITAR

La razón por la que considero mediante un archivo generado en el exterior en el JAR un hack es porque este es) una biblioteca y se integrará en las aplicaciones del cliente. Estas aplicaciones cliente pueden definir sus propios cargadores de clases, lo que significa que no puedo confiar en las reglas de carga de clase JVM estándar.

Mi preferencia personal sería utilizar la fecha del archivo JAR como lo sugiere serg10.

+0

* En mi opinión, es un truco y podría ser eludido o roto por alguien que tenga un archivo con un nombre similar fuera del JAR, pero en el classpath. * ¿En qué entorno de trabajo programa que le preocupan las personas "eludiendo"? " ¿esta? Tener Ant generar el archivo no es un hack en absoluto. Por supuesto, el enfoque manifiesto es aún mejor para Java-ism (y usted puede hacer que Ant automatice eso también). – Hejazzman

Respuesta

15

Estoy a favor del enfoque basado en estándares. Ponga la información de su versión (junto con otras cosas útiles del editor como el número de compilación, el número de revisión de subversión, el autor, los detalles de la compañía, etc.) en el jar Manifest File.

Esta es una especificación de Java bien documentada y entendida. Existe una gran compatibilidad con herramientas para crear archivos de manifiesto (por ejemplo, core Ant task o maven jar plugin). Esto puede ayudar a configurar algunos de los atributos automáticamente - He configurado Maven para poner el número de versión maven del jar, la revisión de Subversion y la marca de tiempo en el manifiesto para mí en tiempo de compilación.

Usted puede leer el contenido del manifiesto en tiempo de ejecución con llamadas API Java estándar - algo así como:

import java.util.jar.*; 

... 

JarFile myJar = new JarFile("nameOfJar.jar"); // various constructors available 
Manifest manifest = myJar.getManifest(); 
Map<String,Attributes> manifestContents = manifest.getAttributes(); 

Para mí, que se siente como una aplicación Java enfoque más estándar, por lo que probablemente resulte más fácil para su posterior mantenedores de código a seguir.

1

A menos que desee ejecutar su fuente Java a través de un preprocesador C/C++ (que es un GRAN NO-NO), utilice el método jar. Hay otras maneras de obtener los recursos correctos de un contenedor para asegurarse de que alguien no puso un recurso duplicado en el classpath. También podría considerar usar el manifiesto Jar para esto. Mi proyecto hace exactamente lo que intenta hacer (con fechas de compilación, revisiones, autor, etc.) utilizando el manifiesto.

Usted querrá utilizar esto:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF"); 

Esto le conseguirá TODOS los manifiestos en la ruta de clase. Puedes averiguar de qué jar pueden obtener al analizar la URL.

2

AFAIK no hay una manera de hacer esto con javac. Esto se puede hacer fácilmente con Ant: crearía un objeto de primera clase llamado BuildTimestamp.java y generaría ese archivo en tiempo de compilación a través de un objetivo Ant.

Here's an Ant type que serán útiles.

1

Personalmente, buscaría un archivo de propiedades separado en su jar que cargaría en tiempo de ejecución ... El cargador de clases tiene un orden definido para buscar archivos. No recuerdo cómo funciona exactamente a mano, pero no creo que otro archivo con el mismo nombre en algún lugar de la ruta de clases pueda causar problemas.

Pero otra forma de hacerlo sería utilizar Ant para copiar sus archivos .java en un directorio diferente antes de compilarlos, filtrando en constantes String según corresponda. Puede usar algo como:

public String getBuildDateTime() { 
    return "@[email protected]"; 
} 

y escriba un filtro en su archivo Ant para reemplazarlo con una propiedad de compilación.

0

Una sugerencia que tengo de un compañero de trabajo era para obtener el archivo de hormigas para crear un archivo en la ruta de clase y para empaquetar que en el frasco y lo han leído por el método . ... En mi opinión ese es un truco y podría ser eludido/roto por alguien que tenga un archivo similarmente llamado fuera del JAR, pero en el classpath .

No estoy seguro de que conseguir que Ant genere un archivo es un hack terriblemente atroz, si es un hack en absoluto. ¿Por qué no generar un archivo de propiedades y usar java.util.Properties para manejarlo?

1

Quizás una forma más de estilo Java de indicar la versión de su biblioteca sea agregar un número de versión al manifiesto del JAR, como se describe en el manifest documentation.

10

Recuerdo haber visto algo similar en un proyecto de código abierto:

class Version... { 
    public static String tstamp() { 
    return "@[email protected]"; 
    } 
} 

en un archivo de plantilla. Con el filtrado de hormiga copia que puede dar esta macro un valor:

<copy src="templatefile" dst="Version.java" filtering="true"> 
    <filter token="BUILDTIME" value="${build.tstamp}" /> 
</copy> 

uso esto para crear un archivo de origen Version.java en su proceso de construcción, antes de que el paso de compilación.

Cuestiones relacionadas