166 votes

Le fichier dans le jar n'est pas visible pour spring

Tous

J'ai créé un fichier jar avec le MANIFEST.MF suivant à l'intérieur :

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

Dans sa racine, il y a un fichier appelé my.config qui est référencé dans mon spring-context.xml comme ceci :

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

Si je lance le jar, tout semble correct, sauf le chargement de ce fichier spécifique :

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
  • les classes sont chargées depuis l'intérieur du jar
  • spring et les autres dépendances sont chargées à partir de jars séparés.
  • le contexte de printemps est chargé (new ClassPathXmlApplicationContext("spring-context/applicationContext.xml"))
  • my.properties est chargé dans PropertyPlaceholderConfigurer ("classpath:my.properties")
  • Si je place mon fichier .config en dehors du système de fichiers, et que je change l'url de la ressource en 'file:', tout semble aller bien...

Des conseils ?

297voto

sbk Points 795

Si vos fichiers spring-context.xml et my.config se trouvent dans des bocaux différents, vous devrez utiliser la fonction classpath*:my.config ?

Plus d'informations aquí

Assurez-vous également que vous utilisez resource.getInputStream() no resource.getFile() lors du chargement depuis l'intérieur d'un fichier jar.

85voto

taozi Points 671

Dans le paquet de pots de printemps, j'utilise les nouveaux éléments suivants ClassPathResource(filename).getFile() ce qui déclenche l'exception :

ne peut être résolu en chemin de fichier absolu car il ne réside pas dans le système de fichiers : jar

Mais en utilisant new ClassPathResource(filename).getInputStream() résoudra ce problème. La raison est que le fichier de configuration dans le jar n'existe pas dans l'arborescence des fichiers du système d'exploitation, et qu'il faut donc utiliser la fonction getInputStream() .

72voto

jmathewt Points 897

Je sais que cette question a déjà reçu une réponse. Cependant, pour ceux qui utilisent spring boot, ce lien m'a aidé - https://smarterco.de/java-load-file-classpath-spring-boot/

Toutefois, le resourceLoader.getResource("classpath:file.txt").getFile(); était la cause de ce problème et le commentaire de sbk :

C'est ça. Un java.io.File représente un fichier sur le système de fichiers, dans une structure de répertoire. Le bocal est un fichier java.io.File. Mais tout ce qui se trouve dans ce fichier est hors de portée de java.io.File. Pour autant que java soit tant qu'elle n'est pas décompressée, une classe dans un fichier jar n'est pas n'est pas différente d'un mot dans un document Word.

m'a aidé à comprendre pourquoi utiliser getInputStream() à la place. Cela fonctionne pour moi maintenant !

Merci !

16voto

Raphael Points 1262

Le message d'erreur est correct (même s'il n'est pas très utile) : le fichier que nous essayons de charger est le suivant no un fichier sur le système de fichiers, mais un morceau d'octets dans un ZIP à l'intérieur d'un ZIP.

En expérimentant (Java 11, Spring Boot 2.3.x), j'ai trouvé que cela fonctionnait sans changer aucune configuration ou même un caractère générique :

var resource = ResourceUtils.getURL("classpath:some/resource/in/a/dependency");
new BufferedReader(
  new InputStreamReader(resource.openStream())
).lines().forEach(System.out::println);

3voto

Brad Parks Points 5513

J'avais un problème de chargement récursif de ressources dans mon application Spring, et j'ai trouvé que le problème était que je devais utiliser resource.getInputStream . Voici un exemple montrant comment lire de manière récursive tous les fichiers du répertoire config/myfiles qui sont json des fichiers.

Exemple.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;
  }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X