Jar olarak çalışırken sınıf yolu kaynağı bulunamadı


128

Hem Spring Boot 1.1.5 hem de 1.1.6'da bu sorunu yaşıyorum - Uygulamayı STS (3.6.0, Windows) içinden çalıştırdığımda gayet iyi çalışan bir @Value ek açıklamasını kullanarak bir sınıf yolu kaynağı yüklüyorum. Ancak, bir mvn paketi çalıştırıp daha sonra kavanozu çalıştırmayı denediğimde FileNotFound istisnaları alıyorum.

Kaynak, message.txt, src / main / kaynaklardadır. Jar'ı inceledim ve en üst düzeyde (application.properties ile aynı düzeyde) "message.txt" dosyasını içerdiğini doğruladım.

İşte uygulama:

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application implements CommandLineRunner {

    private static final Logger logger = Logger.getLogger(Application.class);

    @Value("${message.file}")
    private Resource messageResource;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... arg0) throws Exception {
        // both of these work when running as Spring boot app from STS, but
        // fail after mvn package, and then running as java -jar
        testResource(new ClassPathResource("message.txt"));
        testResource(this.messageResource);
    }

    private void testResource(Resource resource) {
        try {
            resource.getFile();
            logger.debug("Found the resource " + resource.getFilename());
        } catch (IOException ex) {
            logger.error(ex.toString());
        }
    }
}

İstisna:

c:\Users\glyoder\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-proble
m\target>java -jar demo-0.0.1-SNAPSHOT.jar

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.5.RELEASE)

2014-09-16 08:46:34.635  INFO 5976 --- [           main] demo.Application
                  : Starting Application on 8W59XV1 with PID 5976 (C:\Users\glyo
der\Documents\workspace-sts-3.5.1.RELEASE\classpath-resource-problem\target\demo
-0.0.1-SNAPSHOT.jar started by glyoder in c:\Users\glyoder\Documents\workspace-s
ts-3.5.1.RELEASE\classpath-resource-problem\target)
2014-09-16 08:46:34.640 DEBUG 5976 --- [           main] demo.Application
                  : Running with Spring Boot v1.1.5.RELEASE, Spring v4.0.6.RELEA
SE
2014-09-16 08:46:34.681  INFO 5976 --- [           main] s.c.a.AnnotationConfigA
pplicationContext : Refreshing org.springframework.context.annotation.Annotation
ConfigApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014];
root of context hierarchy
2014-09-16 08:46:35.196  INFO 5976 --- [           main] o.s.j.e.a.AnnotationMBe
anExporter        : Registering beans for JMX exposure on startup
2014-09-16 08:46:35.210 ERROR 5976 --- [           main] demo.Application
                  : java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.211 ERROR 5976 --- [           main] demo.Application
                  : java.io.FileNotFoundException: class path resource [message.
txt] cannot be resolved to absolute file path because it does not reside in the
file system: jar:file:/C:/Users/glyoder/Documents/workspace-sts-3.5.1.RELEASE/cl
asspath-resource-problem/target/demo-0.0.1-SNAPSHOT.jar!/message.txt
2014-09-16 08:46:35.215  INFO 5976 --- [           main] demo.Application
                  : Started Application in 0.965 seconds (JVM running for 1.435)

2014-09-16 08:46:35.217  INFO 5976 --- [       Thread-2] s.c.a.AnnotationConfigA
pplicationContext : Closing org.springframework.context.annotation.AnnotationCon
figApplicationContext@1c77b086: startup date [Tue Sep 16 08:46:34 EDT 2014]; roo
t of context hierarchy
2014-09-16 08:46:35.218  INFO 5976 --- [       Thread-2] o.s.j.e.a.AnnotationMBe
anExporter        : Unregistering JMX-exposed beans on shutdown

Yanıtlar:


201

resource.getFile()kaynağın kendisinin dosya sisteminde kullanılabilir olmasını bekler, yani bir jar dosyasının içine yerleştirilemez. Bu nedenle, uygulamanızı STS'de çalıştırdığınızda çalışır ancak uygulamanızı oluşturup çalıştırılabilir kavanozdan çalıştırdıktan sonra çalışmaz. Aksine kullanmaktan daha getFile()kaynağın içeriğine erişmek için, kullanıyorum tavsiye ederim getInputStream()yerine. Bu, nerede bulunursa bulunsun kaynağın içeriğini okumanıza izin verir.


6
Benim durumumda, anahtar deposu dosyasına giden bir yol sağlamam gerekiyor (tomcat https konektörü uğruna). Jks dosyasını jar'ımın içine sarmak istiyorum. Yukarıdaki çözüme göre bu mümkün değil. Bunu yapmanın ek yollarını biliyor musunuz?
Modi

1
Çok benzer bir gereksinimim var ve anahtar deposunu kavanozun bir parçası olarak ayarlamanıza izin veren hiçbir api yok. @Modi, herhangi bir çözüm bulabildin mi?
Robin Varghese

Anahtar deposu kullanım örneğini mi kastediyorsunuz? Spring Boot'u Tomcat ile mi kullanıyorsunuz?
Modi

@RobinVarghese probleminize herhangi bir çözüm buldunuz mu? Çözülecek benzer bir kullanım durumum var. Bir öneriniz varsa takdir edin.
ufuk7

Tomcat'in https'yi etkinleştirmek için anahtar deposu konumuna ihtiyaç duyması durumunda classpath:filename, anahtar deposu dosyasının jar içinden okunabilmesi için biri kullanılabilir .
ufuk7

60

Bahar çerçeve kullanıyorsanız o zaman okuma ClassPathResourcebir içine Stringkullanarak oldukça basit olan Bahar çerçeve enFileCopyUtils :

String data = "";
ClassPathResource cpr = new ClassPathResource("static/file.txt");
try {
    byte[] bdata = FileCopyUtils.copyToByteArray(cpr.getInputStream());
    data = new String(bdata, StandardCharsets.UTF_8);
} catch (IOException e) {
    LOG.warn("IOException", e);
}

Dosyanın nereye oturması gerektiğine dair bir kısıtlama var mı? Sınıf yolunda herhangi bir yerde olabilir mi? Projenin kökeninde olabilir mi?
Stephane

Sınıf yolunda herhangi bir yerde olabilir.
anubhava

45

Bir dosya kullanmak istiyorsanız:

ClassPathResource classPathResource = new ClassPathResource("static/something.txt");

InputStream inputStream = classPathResource.getInputStream();
File somethingFile = File.createTempFile("test", ".txt");
try {
    FileUtils.copyInputStreamToFile(inputStream, somethingFile);
} finally {
    IOUtils.closeQuietly(inputStream);
}

7

Spring boot projesi bir jar olarak çalıştığında ve sınıf yolunda bir dosya okumaya ihtiyaç duyduğunda, onu aşağıdaki kodla uygularım

Resource resource = new ClassPathResource("data.sql");
BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
reader.lines().forEach(System.out::println);

3

Dosyaları sınıf yolundan kolay okunabilir hale getirmek için java 8 biçiminde bir ClassPathResourceReader sınıfı oluşturdum

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;

import org.springframework.core.io.ClassPathResource;

public final class ClassPathResourceReader {

    private final String path;

    private String content;

    public ClassPathResourceReader(String path) {
        this.path = path;
    }

    public String getContent() {
        if (content == null) {
            try {
                ClassPathResource resource = new ClassPathResource(path);
                BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()));
                content = reader.lines().collect(Collectors.joining("\n"));
                reader.close();
            } catch (IOException ex) {
                throw new RuntimeException(ex);
            }
        }
        return content;
    }
}

Kullanımı:

String content = new ClassPathResourceReader("data.sql").getContent();

2

Ben de bu sınırlamayla karşılaştım ve sorunun üstesinden gelmek için bu kitaplığı oluşturdum: spring-boot-jar-kaynakları Temel olarak, gerektiğinde JAR'dan sınıf yolu kaynaklarını şeffaf bir şekilde çıkaran Spring Boot ile özel bir ResourceLoader kaydetmenize olanak tanır.


2
to get list of data from src/main/resources/data folder --
first of all mention your folder location in properties file as - 
resourceLoader.file.location=data

inside class declare your location. 

@Value("${resourceLoader.file.location}")
    @Setter
    private String location;

    private final ResourceLoader resourceLoader;

public void readallfilesfromresources() {
       Resource[] resources;

        try {
            resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:" + location + "/*.json");
            for (int i = 0; i < resources.length; i++) {
                try {
                InputStream is = resources[i].getInputStream();
                byte[] encoded = IOUtils.toByteArray(is);
                String content = new String(encoded, Charset.forName("UTF-8"));
                }
            }
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
}

1

Jersey kavanozlarının ambalajından çıkarılması gerekiyor.

<build>  
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <requiresUnpack>
                    <dependency>
                        <groupId>com.myapp</groupId>
                        <artifactId>rest-api</artifactId>
                    </dependency>
                </requiresUnpack>
            </configuration>
        </plugin>
    </plugins>
</build>  

0
in spring boot :

1) if your file is ouside jar you can use :        

@Autowired
private ResourceLoader resourceLoader;

**.resource(resourceLoader.getResource("file:/path_to_your_file"))**

2) if your file is inside resources of jar you can `enter code here`use :

**.resource(new ClassPathResource("file_name"))**

0

Andy'nin cevabına dayanarak, bir dizin altındaki tüm YAML'lerin giriş akışlarını ve kaynaklardaki alt dizinleri almak için aşağıdakileri kullandım (Geçilen yolun ile başlamadığını unutmayın /):

private static Stream<InputStream> getInputStreamsFromClasspath(
        String path,
        PathMatchingResourcePatternResolver resolver
) {
    try {
        return Arrays.stream(resolver.getResources("/" + path + "/**/*.yaml"))
                .filter(Resource::exists)
                .map(resource -> {
                    try {
                        return resource.getInputStream();
                    } catch (IOException e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull);
    } catch (IOException e) {
        logger.error("Failed to get definitions from directory {}", path, e);
        return Stream.of();
    }
}

0

Ben de benzer durumda kaldım, ancak tam olarak benzer olmadım, kaynaklar klasöründen bir JSON dosyası okumak istedim. Src / main / kaynaklar Bu nedenle, aşağıda buna benzer bir kod yazdım.

Bir dosyayı okumak için burada listelenen çeşitli yollar vardır fSpring Boot Uygulamasında sınıf yolundan .

@Value ("sınıf yolu: test.json") özel Kaynak kaynağı;

File file = resource.getFile();

@Value("classpath:test.json")

özel Kaynak kaynağı;

File file = resource.getFile();

Şimdi, bu kod, mvn: spring-boot: run kullanarak çalıştırdığımda tamamen iyi çalışıyor, ancak uygulamayı maven kullanarak oluşturup paketledim ve basit bir yürütülebilir jar olarak çalıştırdığım anda bir istisna alıyorum. Şimdi devam edelim ve çözümü bulalım.

InputStream'i kullanmak benim durumumda cevabı bulduğum şey: -

@Value("classpath:test.json")
    Resource resourceFile;

private void testResource(Resource resource) {
        try {
            InputStream resourcee = resource.getInputStream();
            String text = null;
            try (final Reader reader = new InputStreamReader(resourcee)) {
                text = CharStreams.toString(reader);
            }
            System.out.println(text);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Bahar Yağ Kavanozu Kavramı Üzerine Çalışır, bu nedenle Eclipse'de ve siz kavanoz gibi koşarken farklı davrandığı için gerçekten Zor.


0

Orijinal hata mesajı ile ilgili olarak

dosya sisteminde bulunmadığı için mutlak dosya yoluna çözümlenemez

Aşağıdaki kod, yol sorununun çözümünü bulmak için yardımcı olabilir:

Paths.get("message.txt").toAbsolutePath().toString();

Bununla, uygulamanın eksik dosyayı nerede beklediğini belirleyebilirsiniz. Bunu uygulamanızın ana yönteminde gerçekleştirebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.