L'image native GraalVM échoue sur la dépendance Springdoc

Aug 18 2020

J'essaie de créer un exemple d'application à l'aide de Spring Boot et GraalVM Native Image, mais dès que j'ajoute la dépendance pour Springdoc, l'exécutable généré ne fonctionne plus pour les raisons suivantes:

 java.lang.IllegalStateException: Error processing condition on org.springdoc.core.SpringDocConfiguration.springdocBeanFactoryPostProcessor2
        at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60) ~[poc-graalvm-native.exe:na]
        at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[na:na]
        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForBeanMethod(ConfigurationClassBeanDefinitionReader.java:184) ~[na:na]
        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:144) ~[na:na]
        at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:120) ~[na:na]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:331) ~[poc-graalvm-native.exe:na]
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:236) ~[poc-graalvm-native.exe:na]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:280) ~[na:na]
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:96) ~[na:na]
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:707) ~[na:na]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:533) ~[na:na]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:143) ~[na:na]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[poc-graalvm-native.exe:na]
        at c.b.t.graal.GraalVMApplicationPoc.main(GraalVMApplicationPoc.java:31) [poc-graalvm-native.exe:na]
Caused by: java.lang.IllegalStateException: java.io.FileNotFoundException: class path resource [org/springdoc/core/CacheOrGroupedOpenApiCondition$OnCacheDisabled.class] cannot be opened because it does not exist at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.getMetadata(AbstractNestedCondition.java:149) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.getMemberConditions(AbstractNestedCondition.java:121) ~[poc-graalvm-native.exe:na] at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.<init>(AbstractNestedCondition.java:114) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition.getMatchOutcome(AbstractNestedCondition.java:62) ~[poc-graalvm-native.exe:na]
        at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47) ~[poc-graalvm-native.exe:na]
        ... 18 common frames omitted
Caused by: java.io.FileNotFoundException: class path resource [org/springdoc/core/CacheOrGroupedOpenApiCondition$OnCacheDisabled.class] cannot be opened because it does not exist at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:180) ~[poc-graalvm-native.exe:na] at org.springframework.core.type.classreading.SimpleMetadataReader.getClassReader(SimpleMetadataReader.java:55) ~[na:na] at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:49) ~[na:na] at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:103) ~[na:na] at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:81) ~[na:na] at org.springframework.boot.autoconfigure.condition.AbstractNestedCondition$MemberConditions.getMetadata(AbstractNestedCondition.java:146) ~[poc-graalvm-native.exe:na]
        ... 22 common frames omitted

Mes dépendances actuelles sont:

dependencies {
    implementation ('org.springframework.boot:spring-boot-starter-web') {
        exclude group : 'org.apache.tomcat.embed', module : 'tomcat-embed-websocket'
    }
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    // Lombok
    compileOnly("org.projectlombok:lombok")
    annotationProcessor("org.projectlombok:lombok")

    testCompileOnly("org.projectlombok:lombok")
    testAnnotationProcessor("org.projectlombok:lombok")

    // https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j
    implementation('org.slf4j:jcl-over-slf4j:2.0.0-alpha1')
    implementation('org.springdoc:springdoc-openapi-webmvc-core:1.4.4')
}

Tout fonctionnait bien jusqu'à ce que j'ajoute SpringDoc. J'ai déjà essayé d'ajouter des packages springdoc à --initialize-at-build-time sans succès.

J'utilise com.github.ayltai.spring-graalvm-native-plugin pour gérer la tâche gradle et mes dépendances sont:

dependencies {
    implementation ('org.springframework.boot:spring-boot-starter-web') {
        exclude group : 'org.apache.tomcat.embed', module : 'tomcat-embed-websocket'
    }
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    // Lombok
    compileOnly("org.projectlombok:lombok")
    annotationProcessor("org.projectlombok:lombok")

    testCompileOnly("org.projectlombok:lombok")
    testAnnotationProcessor("org.projectlombok:lombok")

    // https://mvnrepository.com/artifact/org.slf4j/jcl-over-slf4j
    implementation('org.slf4j:jcl-over-slf4j:2.0.0-alpha1')
    implementation('org.springdoc:springdoc-openapi-webmvc-core:1.4.4')
}

Tout indice serait apprécié.

Réponses

1 brianbro Aug 31 2020 at 09:25

Pour le moment, il n'y a pas de plugin Spring Gradle officiel, car l'intégration des applications Spring avec graalVM est toujours en mode expérimental et pourrait rencontrer beaucoup d'autres problèmes.

L'erreur que vous rencontrez est que votre image de configuration native n'est pas complète.

Vous pouvez utiliser le spring-graalvm-native, qui est pris en charge par Spring Team, et qui fonctionne comme un charme avec springdoc-openapi:

L'utilisation est expliquée ici:

  • https://repo.spring.io/milestone/org/springframework/experimental/spring-graalvm-native-docs/0.7.1/spring-graalvm-native-docs-0.7.1.zip!/reference/index.html#_guides

Pour la classe que vous mentionnez, vous devriez avoir dans le fichier reflect-config.json:

{
"name": "org.springdoc.core.CacheOrGroupedOpenApiCondition",
"methods": [
  {
    "name": "<init>",
    "parameterTypes": []
  }
]
}

Et sur le resource-config.json:

{"pattern":"\\Qorg/springdoc/core/CacheOrGroupedOpenApiCondition$OnCacheDisabled.class\\E"}, {"pattern":"\\Qorg/springdoc/core/CacheOrGroupedOpenApiCondition$OnMultipleOpenApiSupportCondition.class\\E"}, 
{"pattern":"\\Qorg/springdoc/core/CacheOrGroupedOpenApiCondition.class\\E"}