El archivo dentro del frasco no es visible para la primavera

103

Todas

Creé un archivo jar con el siguiente MANIFEST.MF dentro:

Manifest-Version: 1.0
Ant-Version: Apache Ant 1.8.3
Created-By: 1.6.0_25-b06 (Sun Microsystems Inc.)
Main-Class: my.Main
Class-Path: . lib/spring-core-3.2.0.M2.jar lib/spring-beans-3.2.0.M2.jar

En su raíz hay un archivo llamado my.config al que se hace referencia en mi spring-context.xml así:

<bean id="..." class="...">
    <property name="resource" value="classpath:my.config" />
</bean>

Si ejecuto el jar, todo se ve bien, excepto la carga de ese archivo específico:

Caused by: java.io.FileNotFoundException: class path resource [my.config] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/D:/work/my.jar!/my.config
        at org.springframework.util.ResourceUtils.getFile(ResourceUtils.java:205)
    at org.springframework.core.io.AbstractFileResolvingResource.getFile(AbstractFileResolvingResource.java:52)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:32)
    at eu.stepman.server.configuration.BeanConfigurationFactoryBean.getObject(BeanConfigurationFactoryBean.java:1)
    at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:142)
    ... 22 more
  • las clases se cargan desde el interior del tarro
  • primavera y otras dependencias se cargan desde frascos separados
  • se carga el contexto de primavera (nuevo ClassPathXmlApplicationContext ("contexto de primavera / applicationContext.xml"))
  • my.properties se carga en PropertyPlaceholderConfigurer ("classpath: my.properties")
  • si pongo mi archivo .config fuera del sistema de archivos y cambio la URL del recurso a 'archivo:', todo parece estar bien ...

¿Algun consejo?

BTakacs
fuente

Respuestas:

211

Si sus archivos spring-context.xml y my.config están en frascos diferentes, entonces deberá usar classpath*:my.config?

Más info aquí

Además, asegúrese de que está utilizando resource.getInputStream()no resource.getFile()cuando se carga desde el interior de un archivo JAR.

sbk
fuente
1
Están en el mismo jar, pero probé su solución con el mismo resultado: java.io.FileNotFoundException: class path resource [classpath *: my.config] no se puede resolver en URL porque no existe
BTakacs
14
Mirando de nuevo, parte de su código de llamada (posiblemente BeanConfigurationFactoryBean) está intentando cargar un archivo java.io.File. Archivo se refiere a archivos en el sistema de archivos, que no son entradas en un jar. El código de llamada debería usar resource.getInputStream en lugar de cargarse desde un frasco.
sbk
57
... y ESTA es la respuesta ... ¡Gracias! Dentro de un frasco no use resource.getFile () :-)
BTakacs
2
alguna posibilidad de que haya un "¿por qué?" detrás de no usar getFile () dentro de un frasco? ¿Es simplemente que el archivo está dentro del Jar y, por lo tanto, el "archivo" es el archivo jar?
RockMeetHardplace
8
Eso es. Un archivo java.io.File representa un archivo en el sistema de archivos, en una estructura de directorio. El Jar es un archivo java.io. Pero cualquier cosa dentro de ese archivo está fuera del alcance de java.io.File. En lo que respecta a Java, hasta que se descomprima, una clase en un archivo jar no es diferente a una palabra en un documento de Word.
sbk
50

Sé que esta pregunta ya ha sido respondida. Sin embargo, para aquellos que usan Spring Boot, este enlace me ayudó: https://smarterco.de/java-load-file-classpath-spring-boot/

Sin embargo, resourceLoader.getResource("classpath:file.txt").getFile();estaba causando este problema y el comentario de sbk:

Eso es. Un archivo java.io.File representa un archivo en el sistema de archivos, en una estructura de directorio. El Jar es un archivo java.io. Pero cualquier cosa dentro de ese archivo está fuera del alcance de java.io.File. En lo que respecta a Java, hasta que se descomprima, una clase en un archivo jar no es diferente a una palabra en un documento de Word.

me ayudó a entender por qué usarlo getInputStream()en su lugar. ¡Funciona para mi ahora!

¡Gracias!

jmathewt
fuente
37

En el paquete spring jar, uso new ClassPathResource(filename).getFile(), que lanza la excepción:

no se puede resolver en una ruta de archivo absoluta porque no reside en el sistema de archivos: jar

Pero usar new ClassPathResource(filename).getInputStream()resolverá este problema. La razón es que el archivo de configuración en el jar no existe en el árbol de archivos del sistema operativo, por lo que debe usar getInputStream().

tao zeng
fuente
2

Tuve un problema similar al usar Tomcat6.xy ninguno de los consejos que encontré me ayudó. Al final eliminé la workcarpeta (de Tomcat) y el problema desapareció.

Sé que es ilógico, pero para fines de documentación ...

takacsot
fuente
1

La respuesta de @sbk es la forma en que deberíamos hacerlo en el entorno de arranque de primavera (aparte de @Value ("$ {classpath *:})), en mi opinión. Pero en mi escenario no funcionaba si se ejecutaba de forma independiente jar .. tal vez hice algo mal.

Pero esta puede ser otra forma de hacerlo,

InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);
Abhishek Chatterjee
fuente
1

Tenía un problema más complejo porque tengo más de un archivo con el mismo nombre, uno está en el frasco principal de Spring Boot y otros están en frascos dentro del frasco principal principal. Mi solución fue obtener todos los recursos con el mismo nombre y luego obtener el que necesitaba filtrar por nombre de paquete. Para obtener todos los archivos:

ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);
Enrique Jiménez Flores
fuente
0

Tenía un problema al cargar recursos de forma recursiva en mi aplicación Spring y descubrí que el problema era que debería usar resource.getInputStream. A continuación, se muestra un ejemplo que muestra cómo leer de forma recursiva todos los archivos config/myfilesque son jsonarchivos.

Example.java

private String myFilesResourceUrl = "config/myfiles/**/";
private String myFilesResourceExtension = "json";

ResourceLoader rl = new ResourceLoader();

// Recursively get resources that match. 
// Big note: If you decide to iterate over these, 
// use resource.GetResourceAsStream to load the contents
// or use the `readFileResource` of the ResourceLoader class.
Resource[] resources = rl.getResourcesInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

// Recursively get resource and their contents that match. 
// This loads all the files into memory, so maybe use the same approach 
// as this method, if need be.
Map<Resource,String> contents = rl.getResourceContentsInResourceFolder(myFilesResourceUrl, myFilesResourceExtension);

ResourceLoader.java

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.StreamUtils;

public class ResourceLoader {
  public Resource[] getResourcesInResourceFolder(String folder, String extension) {
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
      String resourceUrl = folder + "/*." + extension;
      Resource[] resources = resolver.getResources(resourceUrl);
      return resources;
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public String readResource(Resource resource) throws IOException {
    try (InputStream stream = resource.getInputStream()) {
      return StreamUtils.copyToString(stream, Charset.defaultCharset());
    }
  }

  public Map<Resource, String> getResourceContentsInResourceFolder(
      String folder, String extension) {
    Resource[] resources = getResourcesInResourceFolder(folder, extension);

    HashMap<Resource, String> result = new HashMap<>();
    for (var resource : resources) {
      try {
        String contents = readResource(resource);
        result.put(resource, contents);
      } catch (IOException e) {
        throw new RuntimeException("Could not load resource=" + resource + ", e=" + e);
      }
    }
    return result;
  }
}
Brad Parks
fuente
0

Tuve el mismo problema, terminé usando los recursos de guayaba mucho más convenientes :

Resources.getResource("my.file")
Ahmad Abdelghany
fuente