kubernetes-client icon indicating copy to clipboard operation
kubernetes-client copied to clipboard

Add graalvm-reachability-metadata for kubernetes client

Open dpalmmna opened this issue 1 year ago • 4 comments

Is your enhancement related to a problem? Please describe

Usage of kubernetes client in a graalvm native application.

Describe the solution you'd like

Availability of the meta data to use kubernetes client in the https://github.com/oracle/graalvm-reachability-metadata repository

Describe alternatives you've considered

No response

Additional context

No response

dpalmmna avatar Apr 27 '23 11:04 dpalmmna

Related to #2004

shawkins avatar Apr 27 '23 11:04 shawkins

For one of my projects I retro fitted the reflection data in a Spring Boot v3 project:

@Compontent
@ImportRuntimeHints(KubernetesClientRuntimeHintsRegistrar::class)
class Test

object KubernetesClientRuntimeHintsRegistrar : RuntimeHintsRegistrar {

    private val logger = KotlinLogging.logger { }

    override fun registerHints(hints: RuntimeHints, classLoader: ClassLoader?) {
        hints.resources().registerPattern("META-INF/services/io.fabric8.kubernetes.api.model.KubernetesResource")
        hints.resources().registerPattern("META-INF/services/io.fabric8.kubernetes.client.http.HttpClient\$Factory")
        hints.reflection().registerType<VersionInfo>(*MemberCategory.values())
        registerClients(hints)
        registerJacksonKubernetesModels(hints)
    }

    private fun registerClients(hints: RuntimeHints) {
        val clazz = Client::class.java
        val reflections = Reflections(clazz.packageName, clazz)
        val clients = reflections.getSubTypesOf(Client::class.java) + Client::class.java

        for (client in clients) {
            hints.reflection().registerType(client, *MemberCategory.values())
            logger.info { "registering ${client.name} for reflection" }
        }
    }

    private fun registerJacksonKubernetesModels(hints: RuntimeHints) {
        val clazz = KubernetesResource::class.java
        val reflections = Reflections(clazz.packageName, clazz)
        val kubernetesModels = reflections.getSubTypesOf(KubernetesResource::class.java)
        val combined = buildSet {
            addAll(kubernetesModels)
            addAll(resolveSerializationClasses<JsonSerialize>(reflections))
            addAll(resolveSerializationClasses<JsonDeserialize>(reflections))
        }

        for (model in combined) {
            hints.reflection().registerType(model, *MemberCategory.values())
            logger.info { "registering ${model.name} for reflection" }
        }
    }

    /**
     * Extracts Jacksons Deserializer / Serializers specified in the classes annotations
     */
    private inline fun <reified R : Annotation> resolveSerializationClasses(reflections: Reflections): List<Class<*>> {
        val clazz = R::class.java
        val method = clazz.getMethod("using")
        val classes = reflections.getTypesAnnotatedWith(clazz)

        return classes.mapNotNull { clazzWithAnnotation ->
            val annotation = clazzWithAnnotation.getAnnotation(clazz)
            if (annotation != null) method.invoke(annotation) as Class<*> else null
        }
    }
}

Its not the best solution, as its tied to Spring Boot. But the approach in general works that way. It is highly inspired by josh long.
There also is a project which might be interesting here: https://github.com/GoodforGod/graalvm-hint It uses an annotation processor to dynamically create a reflect config file

cmdjulian avatar Jun 14 '23 12:06 cmdjulian

This issue has been automatically marked as stale because it has not had any activity since 90 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions!

stale[bot] avatar Sep 13 '23 20:09 stale[bot]

This issue has been automatically marked as stale because it has not had any activity since 90 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions!

stale[bot] avatar Dec 20 '23 01:12 stale[bot]

This issue has been automatically marked as stale because it has not had any activity since 90 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions!

stale[bot] avatar Jun 13 '24 02:06 stale[bot]