diff --git a/src/main/java/io/github/hectorvent/floci/services/pricing/PricingService.java b/src/main/java/io/github/hectorvent/floci/services/pricing/PricingService.java index 26c9bd1f3..482cea951 100644 --- a/src/main/java/io/github/hectorvent/floci/services/pricing/PricingService.java +++ b/src/main/java/io/github/hectorvent/floci/services/pricing/PricingService.java @@ -492,7 +492,14 @@ JsonNode readJson(String relativePath, ObjectMapper mapper) throws IOException { } } String resource = "pricing-snapshots/" + relativePath; - try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource)) { + // Use the class's own loader rather than the thread's context loader. + // In a GraalVM native image the thread context loader can be the + // bootstrap loader, which sees no application resources, while the + // class's loader sees everything bundled into the image. + ClassLoader cl = PricingService.class.getClassLoader(); + try (InputStream in = cl != null + ? cl.getResourceAsStream(resource) + : ClassLoader.getSystemResourceAsStream(resource)) { if (in == null) { return null; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index adc441521..10806585b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -20,6 +20,12 @@ quarkus: # No 'delay' value is set - observers run synchronously, no artificial sleep is introduced. delay-enabled: true native: + resources: + # The Pricing service reads its bundled snapshot at runtime via + # ClassLoader#getResourceAsStream. Quarkus's static resource analysis + # cannot detect dynamically-built paths, so the tree is registered + # explicitly to ensure GraalVM includes every file in the native image. + includes: pricing-snapshots/** additional-build-args: - --report-unsupported-elements-at-runtime - --allow-incomplete-classpath