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

Doesn't: notworking

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