Classpath resource not found when running as jar

JavaSpring Boot

Java Problem Overview


Having this problem both in Spring Boot 1.1.5 and 1.1.6 - I'm loading a classpath resource using an @Value annotation, which works just fine when I run the application from within STS (3.6.0, Windows). However, when I run a mvn package and then try to run the jar, I get FileNotFound exceptions.

The resource, message.txt, is in src/main/resources. I've inspected the jar and verified that it contains the file "message.txt" at the top level (same level as application.properties).

Here's the application:

@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());
		}
	}
}

The exception:

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

Java Solutions


Solution 1 - Java

resource.getFile() expects the resource itself to be available on the file system, i.e. it can't be nested inside a jar file. This is why it works when you run your application in STS (Spring Tool Suite) but doesn't work once you've built your application and run it from the executable jar. Rather than using getFile() to access the resource's contents, I'd recommend using getInputStream() instead. That'll allow you to read the resource's content regardless of where it's located.

Solution 2 - Java

If you're using Spring framework then reading ClassPathResource into a String is pretty simple using Spring framework's FileCopyUtils:

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);
}

Solution 3 - Java

If you want to use a file:

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);
}

Solution 4 - Java

when spring boot project running as a jar and need read some file in classpath, I implement it by below code

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

Solution 5 - Java

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);
        }
}

Solution 6 - Java

I've create a ClassPathResourceReader class in a java 8 way to make easy read files from classpath

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

Utilization:

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

Solution 7 - Java

I encountered this limitation too and created this library to overcome the issue: spring-boot-jar-resources It basically allows you to register a custom ResourceLoader with Spring Boot that extracts the classpath resources from the JAR as needed, transparently.

Solution 8 - Java

Jersey needs to be unpacked jars.

<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>  

Solution 9 - Java

Another important thing I noticed is that when running the application it ignores capitals in file/folders in the resources folder where it doesn't ignore it while running as a jar. Therefore, in case your file is in the resources folder under Testfolder/messages.txt

@Autowired
ApplicationContext appContext;

// this will work when running the application, but will fail when running as jar
appContext.getResource("classpath:testfolder/message.txt");

Therefore, don't use capitals in your resources or also add those capitals in your constructor of ClassPathResource:

appContext.getResource("classpath:Testfolder/message.txt");

Solution 10 - Java

Solution is correct as per the accepted answer. I am giving my solution to read the Stream to String more efficiently (using StreamUtils) instead of trying to create a temp file and read text.

  @Bean
  public String readFromResource(final @Value("classpath:data/message.txt") Resource messageFile)
      throws IOException {
    return StreamUtils.copyToString(messageFile.getInputStream(), StandardCharsets.UTF_8);
  }

Solution 11 - Java

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"))**

Solution 12 - Java

Based on Andy's answer I used the following to get an input streams of all YAMLs under a directory and sub-directories in resources (Note that the path passed doesn't begin with /):

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();
    }
}

Solution 13 - Java

Regarding to the originally error message

> cannot be resolved to absolute file path because it does not reside in > the file system

The following code could be helpful, to find the solution for the path problem:

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

With this you can determine, where the application expects the missing file. You can execute this in the main method of your application.

Solution 14 - Java

I was facing same error

InputStream inputStream = new ClassPathResource("filename.ext").inputStream();

this should solve FileNotFoundException while running

Solution 15 - Java

this worked for me in a static context:

    InputStream inputStream = ClassName.class.getClassLoader().getResourceAsStream("folderName/fileName.xml");
    Reader reader = new InputStreamReader(inputStream);
    String xml = CharStreams.toString(reader);

Solution 16 - Java

I had faced same issue while running with "java -jar

excel report file template path ./templates/Itemized_Report_2021_V1.xlsx java.io.FileNotFoundException: D:\STS%20WORKSPACE\app\target\classes\templates\Itemized_Report_2021_V1.xlsx (The system cannot find the path specified)

Solution: @Override public void exportExcelReport(HttpServletResponse response, List contexts) throws IOException, URISyntaxException { String templateFilePath = "/templates/Itemized_Report_2021_V1.xlsx"; InputStream resourceFile = getClass().getResourceAsStream(templateFilePath); if (resourceFile == null) { throw new IllegalArgumentException("Template file not found!. " + templateFilePath); } else { ServletOutputStream outputStream = null; try { log.info("Combined report with Competency excel report file template path {}", templateFilePath); this.workbook = new XSSFWorkbook(resourceFile); prepareCompetencyReport(contexts); prepareItemizedReport(contexts);

			// Return as octet-stream format in the rest response
			outputStream = response.getOutputStream();
			workbook.write(outputStream);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} finally {
			workbook.close();
			if (outputStream != null)
				outputStream.close();
		}
	}
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongyoderView Question on Stackoverflow
Solution 1 - JavaAndy WilkinsonView Answer on Stackoverflow
Solution 2 - JavaanubhavaView Answer on Stackoverflow
Solution 3 - JavaJae-il LeeView Answer on Stackoverflow
Solution 4 - JavazhuguoweiView Answer on Stackoverflow
Solution 5 - JavaJayshree PancholiView Answer on Stackoverflow
Solution 6 - JavaTiagoView Answer on Stackoverflow
Solution 7 - JavaUlisesView Answer on Stackoverflow
Solution 8 - JavautkusonmezView Answer on Stackoverflow
Solution 9 - JavaBart BoersmaView Answer on Stackoverflow
Solution 10 - JavaSanjay BharwaniView Answer on Stackoverflow
Solution 11 - JavaMerzouk MENHOURView Answer on Stackoverflow
Solution 12 - Javaaksh1618View Answer on Stackoverflow
Solution 13 - JavaSJXView Answer on Stackoverflow
Solution 14 - Javavaibhav jainView Answer on Stackoverflow
Solution 15 - JavaSebastian JuarezView Answer on Stackoverflow
Solution 16 - JavaSankarView Answer on Stackoverflow