I have the following snippet working properly in a JVM setup:

hello:
  message: classpath:hello/world.txt
@ConfigurationProperties("hello")
data class Config(val message: Resource)

@Configuration
@EnableConfigurationProperties(Config::class)
@ImportRuntimeHints(ResourceConfigRegistrar::class)
class GreeterService(private val config: Config) {

    private val logger = KotlinLogging.logger { }

    @PostConstruct
    fun greet() {
        logger.info { config.message.file.readText() }
    }
}

internal class ResourceConfigRegistrar : RuntimeHintsRegistrar {
    override fun registerHints(hints: RuntimeHints, classLoader: ClassLoader?) {
        hints.resources().registerResource(ClassPathResource("hello/world.txt"))
    }
}

However, for native image it doesn't with the error message: java.io.FileNotFoundException: class path resource [hello/world.txt] cannot be resolved to absolute file path because it does not reside in the file system: resource:/hello/world.txt

When changing the code to the following, it works as intended:

hello:
  message: /hello/world.txt
@ConfigurationProperties("hello")
data class Config(val message: String)

@Configuration
@EnableConfigurationProperties(Config::class)
@ImportRuntimeHints(ResourceConfigRegistrar::class)
class GreeterService(private val config: Config) {

    private val logger = KotlinLogging.logger { }

    @PostConstruct
    fun greet() {
        logger.info { javaClass.getResourceAsStream(config.message)!!.bufferedReader().readText() }
    }
}

internal class ResourceConfigRegistrar : RuntimeHintsRegistrar {
    override fun registerHints(hints: RuntimeHints, classLoader: ClassLoader?) {
        hints.resources().registerResource(ClassPathResource("hello/world.txt"))
    }
}

As I like to use Resource as an abstraction in my code, I think this should work in the native image case as well.
Eventually ClassLoader.getSystemResource(this.absolutePath) or ClassLoader.getSystemClassLoader(); is called by the Spring Resource resolving mechanism. When I do remember correctly, this do not work in native image.
I therefore tried using ClassPathResource("hello/world.txt") directly, also tried ClassPathResource("hello/world.txt", javaClass.classLoader) but all with the same result in native image.

I pushed a sample to cmdjulian/spring-playground on branch resource-loading-native-image. You can run it by executing ./gradlew nativeCompile && build/native/nativeCompile/notes.

Comment From: cmdjulian

Turns out, ResourceConfigRegistrar is actually not needed

Comment From: mhalbritter

When using .getFile(), you assume that a File is available, which is not the case for resources in a native image. The correct way to to it is to use .getInputStream, which returns an InputStream abstraction, which works for all resources (in the file system, in a JAR file, in a native-image, ...).

This code works:

logger.info { config.message.inputStream.readAllBytes().decodeToString() }