I dockerized my Spring Boot App. There is a piece of code that loads a bin file (eg, my-bin-file.bin) and build a model out of it. Whenever I run the standalone app (through run on IntelliJ) it can find the file and build the model. However, when I run it through the Dockerfile, it can't find it and fails.
Dockerfile
WORKDIR /app
COPY target/services-*.war /app/services.war
CMD ["java", "-jar", "services.war"]
File Resource
root
|-- src
|-- java
|-- packages and java files
|-- resource
|-- binFolder
|-- my-bin-file.bin
Bin Loader
public class BinLoader {
public static String[] loadBinFile() throws IOException {
String folder = BinLoader.class.getClassLoader().getResource("binFolder").getFile();
try (InputStream inputStream = new FileInputStream(folder + "my-bin-file.bin")) {
// build model
...
}
}
}
I checked the war file, and it's packaged in there in the expected path. It's inside /WEB-INF/classes/binFolder/my-bin-file.bin
The InputStream fails with NullException
.
I wonder what I'm doing wrong. Any pointers would be much appreciated. Thanks.
The problem is the use of the FileInputStream
. It will use a java.io.File
to try to read the referenced resource, however a java.io.File
expects the referenced resource to be an actual file on a file system. This is the case when you are running from Intellij but not when you are running from a jar or war.
To fix utilize Spring to load the resource from you from the classpath and obtain the InputStream
. To make it easier you can use the ClassPathResource
to directly access it. This will work in both cases, running from Intellij and as jar/war.
public static String[] loadBinFile() throws IOException {
String resource = "/binFolder/my-bin-file.bin";
try (InputStream inputStream = new ClassPathResource(resource).getInputStream()) {
// build model
...
}
}