2010-11-08 8 views
14

utilizo este código en mi programa para cargar un archivo de propiedades:jar ejecutable no encontrarán los archivos de propiedades

Properties properties = new Properties(); 
URL url = new App().getClass().getResource(PROPERTIES_FILE); 
properties.load(url.openStream()); 

El código funciona muy bien en Eclipse. Luego empaqueté el programa en un JAR llamado MyProgram.jar, y lo ejecuté, obtuve una NullPointerException en la segunda línea. El JAR no contiene el archivo de propiedades, ambos están en el mismo directorio. Estoy usando Maven para crear el JAR. ¿Como puedo solucionar este problema?

ACTUALIZACIÓN: No deseo agregar el archivo de propiedades al JAR, ya que se creará en el momento del despliegue.

+2

lateral: ¿Hay alguna razón que usted está usando 'getResource()' en lugar de 'getResourceAsStream()', ya que solo lo estás usando como una secuencia de todos modos? – Powerlord

+1

No, no tengo ningún motivo en particular. –

+0

¿Cómo se ejecuta el contenedor? Si via java -jar, ¿puedes probar java -cp ./MyProgram.jar y ver si funciona? –

Respuesta

23

BalusC tiene razón, debe indicar a Maven que genere un MANIFEST.MF con el directorio actual (.) en la entrada Class-Path:.

Suponiendo que todavía está utilizando la Asamblea plugin Maven y el descriptor jar-with-dependencies para construir su JAR ejecutable, se puede decir que el plugin para hacerlo utilizando la siguiente:

<plugin> 
    <artifactId>maven-assembly-plugin</artifactId> 
    <version>2.2</version> 
    <configuration> 
     <descriptorRefs> 
     <descriptorRef>jar-with-dependencies</descriptorRef> 
     </descriptorRefs> 
     <archive> 
     <manifest> 
      <mainClass>com.stackoverflow.App</mainClass> 
     </manifest> 
     <manifestEntries> 
      <Class-Path>.</Class-Path> <!-- HERE IS THE IMPORTANT BIT --> 
     </manifestEntries> 
     </archive> 
    </configuration> 
    <executions> 
     <execution> 
     <id>make-assembly</id> <!-- this is used for inheritance merges --> 
     <phase>package</phase> <!-- append to the packaging phase. --> 
     <goals> 
      <goal>single</goal> <!-- goals == mojos --> 
     </goals> 
     </execution> 
    </executions> 
    </plugin> 
+0

Si no está utilizando el complemento de ensamblaje maven, hágamelo saber y actualizaré mi respuesta. –

+0

Con la sección 'executions', no tengo que ejecutar' mvn assembly: assembly' por separado, ¿verdad? Por cierto, gracias por responder todas mis preguntas sobre Maven. –

+1

@HaiMinhNguyen: De hecho, la 'ejecución' anterior vincula el objetivo 'único' en la fase 'paquete'. Como resultado, ejecutar 'mvn package' crea el ensamblado. Oh, y de nada. –

2

EDIT: se trata de responder a su comentario:

Es necesario asegurarse de que el archivo de propiedades se encuentra en la ruta de clase con la raíz correcta para la invocación de Java que está protagonizada por el archivo jar. si su camino es

Cosas/things.properties

y la ubicación en tiempo de ejecución es

/opt/myapp/etc/stuff/things.properties

y el archivo JAR está en

/opt/miaplicacion/bin/myjar

entonces usted necesita para poner en marcha lo

/ruta/a/java -cp "/opt/myapp/etc:/opt/myapp/bin/myjar.jar" my.pkg.KavaMain

trabajar con este tipo de configuraciones puede ser fastidioso en un desarrollador entorno, afortunadamente, está el maven exec plugin que le proporcionará el tipo de escenario de lanzamiento correcto.

respuesta original:

¿Quieres leer sobre the maven resources plugin.

Básicamente desea agregar algo como esto:

<plugin> 
     <artifactId>maven-jar-plugin</artifactId> 
     <configuration> 
       <resources> 
         <resource> 
           <directory>src/main/java</directory> 
           <includes> 
             <include>**/*properties</include> 
           </includes> 
         </resource> 
       </resources> 
     </configuration> 
<plugin> 

a su pom.xml asumiendo que eres Propertis archivo es con sus fuentes de Java - en realidad debería ser en src/main/resources.

+0

Gracias, pero no quiero agregar el archivo de propiedades al JAR. Se cambiará en el momento del despliegue. –

+0

Según su edición: el argumento '-cp' es ** ignorado ** cuando se usa el argumento' -jar'. Realmente tiene que ir en el archivo 'MANIFEST.MF' :) – BalusC

+0

@BalusC righto, arreglado. No puede ir en MANIFEST.MF si se puede mover en tiempo de ejecución. – lscoughlin

17

Hay dos soluciones provisionales :

  1. No utilice el JAR JAR executabele, sino como biblioteca.

    java -cp .;filename.jar com.example.YourClassWithMain 
    
  2. Obtenga la ubicación raíz del archivo JAR y obtener el archivo de propiedades de la misma.

    URL root = getClass().getProtectionDomain().getCodeSource().getLocation(); 
    URL propertiesFile = new URL(root, "filename.properties"); 
    Properties properties = new Properties(); 
    properties.load(propertiesFile.openStream()); 
    

Ninguno de los dos enfoques se recomienda!El enfoque recomendaría es tener la siguiente entrada en el archivo JAR de /META-INF/MANIFEST.MF:

Class-Path: . 

entonces va a ser disponible como recurso de ruta de clase de la forma habitual. Realmente tendrá que instruir a Maven de alguna manera para que genere el archivo MANIFEST.MF así.

+0

Vaya, probé la primera opción antes pero la usé. COMMA filename.jar. Quizás es por eso que no funcionó. Gracias por tu ayuda. –

+0

Hay una razón para evitar el Classpath, es decir, si el contenido cambia entre lecturas. El cargador de recursos almacena en caché el primer contenido –

0

tuve un problema similar, y este hilo fue de gran ayuda! Para su información, he modificado mi Ant Buildfile para hacer el MANIFIESTO de decisiones, entonces designada que se manifiestan cuando JAR-ing mi código de servidor: Nota

<!-- Create a custom MANIFEST.MF file, setting the classpath. --> 
<delete file="${project.base.dir}/resources/MANIFEST.MF" failonerror="false"/> 
<manifest file="${project.base.dir}/resources/MANIFEST.MF"> 
    <attribute name="Class-Path" value="." /> 
</manifest> 

<!-- JAR the server-side code, using the custom manifest from above. --> 
<jar destfile="services/${name}.aar" manifest="${project.base.dir}/resources/MANIFEST.MF"> 
[....] 
Cuestiones relacionadas