I put my index.html
into resources/public
folder, and when running the application (from IDE, or as a fatJAR), everything works as expected when I go to http://localhost:8080/
-> the index.html
gets served to the browser.
The problem arises when I want to use these resources from inside native-image packed .exe file on my Windows machine (using spring-native).
I packed the file properly using declaration inside resource-config.json
as:
{
"resources": [
{
"pattern": "\\Qpublic/index.html\\E"
}
],
"bundles": []
}
But the http://localhost:8080/
page is not serving index.html
out of the box.
The only way, how I currently hardcoded this to show-up is using this code:
@Configuration
@AutoConfigureAfter(DispatcherServletAutoConfiguration.class)
public class Config implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
ResourceResolver resolver = new StreamResResolver();
registry
.addResourceHandler("/**")
.addResourceLocations(
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/")
.resourceChain(false)
.addResolver(resolver);
}
public class StreamResResolver implements ResourceResolver {
@Override
public Resource resolveResource(
HttpServletRequest request,
String requestPath,
List<? extends Resource> locations,
ResourceResolverChain chain) {
Resource resource = resolve(requestPath, locations);
if (resource != null) {
return resource;
}
// try next in chain
resource = chain.resolveResource(request, requestPath, locations);
return resource;
}
@Override
public String resolveUrlPath(
String resourcePath, List<? extends Resource> locations, ResourceResolverChain chain) {
return resourcePath;
}
private Resource resolve(String requestPath, List<? extends Resource> locations) {
try {
URI uri = new URI("static/" + requestPath);
return new ByteArrayResource2(
WebMvcConfig.class
.getClassLoader()
.getResourceAsStream(uri.getPath())
.readAllBytes(),
requestPath);
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
return null;
}
}
public class ByteArrayResource2 extends ByteArrayResource {
private String filename;
public ByteArrayResource2(byte[] byteArray, String filename) {
super(byteArray);
this.filename = filename;
}
@Override
public String getFilename() {
return this.filename;
}
@Override
public long lastModified() {
return 0;
}
}
}
Is there something similar to the code above already included in the Spring? I basically have to load the resources using getResourceAsStream
in order to be able to read that stuff from native-image binary.
Comment From: sdeleuze
Hi, could you please share a repro project of what you tried originally before doing those changes? I would like to understand if you were trying to rely on Spring Boot default configuration for serving resources or on custom WebMvcConfigurer#addResourceHandlers
configuration.
Comment From: bojanv55
@sdeleuze I tried first default Spring Boot config (basically not to setup anything). And this one worked for running from IDE, or when running fatJAR that is packed by Spring. But when I try running .exe file produced by spring-native and GraalVM, it was not working (until in the end I added that WebMvcConfigurer#addResourceHandlers
).
I could put small repro. repo. in Github, but I guess you would need native-image.exe in order to compile it and see how it works in that compiled binary.
Comment From: bojanv55
Here is the code that I use in this gist And here are screens of working version, and one when it doesn't work:
Works:
Doesn't:
Comment From: ttddyy
Hi @bojanv55,
I took your gist and created a repro project here to help diagnosis the issue.
I found it is actually working with Spring Boot 2.6.0-M3
but failed with 2.6.0-SNAPSHOT
.
The snapshot version I used is spring-boot-2.6.0-20211020.003406-368.jar
.
So, some changes in boot between M3 to this snapshot may have introduced the issue.
Comment From: bojanv55
Yes, just tried. Seems that M3 is working, but snapshot doesn't.
Comment From: sdeleuze
I have refined the native configuration and added related tests via https://github.com/spring-projects-experimental/spring-native/commit/84bdde3c17608e2302a2a1e2daaaf4af771a4e8d to catch such breakage as part of https://github.com/spring-projects-experimental/spring-native/issues/1128, but I can't reproduce the issue with Spring Boot latest snapshots.
I will close that issue, please comment on https://github.com/spring-projects-experimental/spring-native/issues/1128 if you still see errors with Boot 2.6.0-SNAPSHOT
with a repro.
Comment From: ttddyy
@bojanv55 @sdeleuze
Interestingly, my repro project failed with GraalVM 21.2.0
but passed with 21.3.0
.
So, the combination it works is:
- Spring Boot 2.6.0-SNAPSHOT
- Spring Native 0.11.0-SNAPSHOT
(custom resource-config.json
is no longer required.)
- Graalvm 21.3.0