Файл внутри банки не виден весной

104

Все

Я создал файл jar со следующим файлом MANIFEST.MF внутри:

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

В его корне находится файл my.config, на который есть ссылка в моем spring-context.xml следующим образом:

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

Если я запустил банку, все будет хорошо, за исключением загрузки этого конкретного файла:

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
  • классы загружаются изнутри банки
  • Spring и другие зависимости загружаются из отдельных jar-файлов
  • контекст Spring загружен (новый ClassPathXmlApplicationContext ("spring-context / applicationContext.xml"))
  • my.properties загружается в PropertyPlaceholderConfigurer ("classpath: my.properties")
  • если я помещу свой файл .config за пределы файловой системы и изменю URL-адрес ресурса на 'file:', все будет в порядке ...

Какие-нибудь советы?

BTakacs
источник

Ответы:

211

Если ваши файлы spring-context.xml и my.config находятся в разных банках, вам нужно будет использовать classpath*:my.config?

Больше информации здесь

Кроме того, убедитесь, что вы используете resource.getInputStream()not resource.getFile()при загрузке из файла jar.

сбк
источник
1
Они находятся в одной банке, но я попробовал ваше решение с тем же результатом: java.io.FileNotFoundException: ресурс пути к классу [classpath *: my.config] не может быть преобразован в URL, потому что он не существует
BTakacs
14
Посмотрев еще раз, часть вашего вызывающего кода (возможно, BeanConfigurationFactoryBean) пытается загрузить файл java.io.File. Файл относится к файлам в файловой системе, которых нет в jar-файлах. Вызывающий код должен использовать resource.getInputStream вместо загрузки из банки.
sbk
58
... и ЭТО ответ ... Спасибо! Внутри банки не используйте resource.getFile () :-)
BTakacs
2
есть шанс, что "почему?" позади не использования getFile () внутри банки? Просто файл находится внутри Jar и, следовательно, "файл" - это файл jar ??
RockMeetHardplace
8
Вот и все. Файл java.io.File представляет собой файл в файловой системе в структуре каталогов. Jar - это файл java.io.File. Но все, что находится в этом файле, недоступно для java.io.File. Что касается java, до тех пор, пока он не будет распакован, класс в файле jar не отличается от слова в текстовом документе.
sbk
50

Я знаю, что на этот вопрос уже дан ответ. Однако для тех, кто использует весеннюю загрузку, эта ссылка помогла мне - https://smarterco.de/java-load-file-classpath-spring-boot/

Однако это resourceLoader.getResource("classpath:file.txt").getFile();вызывало эту проблему и комментарий sbk:

Вот и все. Файл java.io.File представляет собой файл в файловой системе в структуре каталогов. Jar - это файл java.io.File. Но все, что находится в этом файле, недоступно для java.io.File. Что касается java, до тех пор, пока он не будет распакован, класс в файле jar не отличается от слова в текстовом документе.

помогли мне понять, почему использовать getInputStream()вместо этого. У меня теперь работает!

Спасибо!

Jmathewt
источник
38

В пакете spring jar я использую new ClassPathResource(filename).getFile(), который вызывает исключение:

не может быть преобразован в абсолютный путь к файлу, потому что он не находится в файловой системе: jar

Но использование нового ClassPathResource(filename).getInputStream()решит эту проблему. Причина в том, что файл конфигурации в банке не существует в дереве файлов операционной системы, поэтому необходимо использовать getInputStream().

Тао Цзэн
источник
2

У меня была аналогичная проблема при использовании Tomcat6.x, и ни один из найденных мной советов не помог. В конце я удалил workпапку (Tomcat), и проблема исчезла.

Я знаю, что это нелогично, но для документации ...

такачот
источник
1

Ответ @sbk - это то, как мы должны делать это в среде весенней загрузки (кроме @Value ("$ {classpath *:})), на мой взгляд. Но в моем сценарии это не сработало, если выполнение из автономного банка .. может я что то не так сделал.

Но это может быть другой способ сделать это,

InputStream is = this.getClass().getClassLoader().getResourceAsStream(<relative path of the resource from resource directory>);
Абхишек Чаттерджи
источник
1

У меня возникла более сложная проблема, потому что у меня есть несколько файлов с одинаковым именем, один находится в основной банке Spring Boot, а другие - в банках внутри основной толстой банки. Мое решение заключалось в получении всех ресурсов с одинаковыми именами, а после этого получить тот, который мне нужен, с фильтрацией по имени пакета. Чтобы получить все файлы:

ResourceLoader resourceLoader = new FileSystemResourceLoader();
final Enumeration<URL> systemResources = resourceLoader.getClassLoader().getResources(fileNameWithoutExt + FILE_EXT);
Энрике Хименес Флорес
источник
0

У меня возникла проблема с рекурсивной загрузкой ресурсов в моем приложении Spring, и я обнаружил, что проблема в том, что я должен использовать resource.getInputStream. Вот пример , показывающий , как рекурсивно прочитать во всех файлах в config/myfilesкоторые jsonфайлы.

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;
  }
}
Брэд Паркс
источник
0

У меня была такая же проблема, но в итоге я использовал гораздо более удобный ресурсы Guava :

Resources.getResource("my.file")
Ахмад Абдельгани
источник