GraalVM: DependencyInjectionException in native Micronaut application with Micronaut Email #8038
-
Hi 👋🏻 I have a pretty simple Micronaut application containing one controller that forwards a http request to MailJet (using Micronaut Email). @Controller("/api/v1/message")
@Validated
@Slf4j
@RequiredArgsConstructor
public class MailController {
private final EmailSender<?, ?> emailSender;
private final MailConfiguration mailConfiguration;
@Post
public HttpStatus sendMessage(@Valid @Body MessageRequest request) {
log.info("Received message {}", request);
final String mailBody =
"Neue Nachricht von "
+ request.name()
+ " «"
+ request.email()
+ "»."
+ "\n\n"
+ "Betreff: "
+ request.subject()
+ "\n\n"
+ request.message();
emailSender.send(
io.micronaut.email.Email.builder()
.from(mailConfiguration.getFrom())
.to(mailConfiguration.getTo())
.subject("Neue Anfrage auf Webseite von " + request.name())
.body(mailBody));
return HttpStatus.ACCEPTED;
}
@Serdeable
@Introspected
public record MessageRequest(
@NotBlank String name,
@Email String email,
@NotBlank String subject,
@NotBlank String message) {}
} Furthermore I have an immutable configuration instance @ConfigurationProperties(value = MailConfiguration.PREFIX)
public interface MailConfiguration {
String PREFIX = WebsiteConfiguration.PREFIX + ".mail";
@Email
String getTo();
@Email
String getFrom();
} When I run the application as a FatJar everything works as expected. But when I run the native compiled application Micronaut has trouble to inject the
I'm pretty new to native images and due to that I bit stuck with this error. Can you maybe give me some hints how to analyse (and fix) this problem? Btw. I have set the Micronaut context logger to <configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>
<logger name="ch.onstructive.www" level="INFO"/>
<logger name="'io.micronaut.context.condition" level="TRACE"/>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration> My plugins {
id("groovy")
id("com.github.johnrengelman.shadow") version "7.1.2"
id("io.micronaut.application") version "3.5.3"
id "com.diffplug.spotless" version "6.11.0"
}
version = "0.1"
group = "ch.onstructive.www"
dependencies {
annotationProcessor("org.projectlombok:lombok")
annotationProcessor("io.micronaut:micronaut-http-validation")
annotationProcessor("io.micronaut.serde:micronaut-serde-processor")
implementation("io.micronaut:micronaut-http-client")
implementation("io.micronaut.email:micronaut-email-mailjet")
implementation("io.micronaut.serde:micronaut-serde-jackson")
implementation("jakarta.annotation:jakarta.annotation-api")
compileOnly("org.projectlombok:lombok")
runtimeOnly("ch.qos.logback:logback-classic")
implementation("io.micronaut:micronaut-validation")
}
spotless {
java {
removeUnusedImports()
target project.fileTree(project.projectDir) {
include 'src/*/java/**/*.java'
excludes = [
'**/generated/**/*.*',
'**/generated-sources/**/*.*'
]
}
googleJavaFormat()
licenseHeaderFile rootProject.file('license.txt'), "package "
}
}
application {
mainClass.set("ch.onstructive.www.Application")
}
java {
sourceCompatibility = JavaVersion.toVersion("17")
targetCompatibility = JavaVersion.toVersion("17")
}
graalvmNative.toolchainDetection = false
micronaut {
runtime("netty")
testRuntime("spock2")
processing {
incremental(true)
annotations("ch.onstructive.www.*")
}
}
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("io.micronaut:micronaut-jackson-databind"))
.using(module("io.micronaut.serde:micronaut-serde-jackson:1.3.2"))
}
} Update 1 I use Docker to build the native image. This is the auto generated FROM ghcr.io/graalvm/native-image:ol7-java17-22.2.0 AS graalvm
WORKDIR /home/app
COPY layers/libs /home/app/libs
COPY layers/classes /home/app/classes
COPY layers/resources /home/app/resources
COPY layers/application.jar /home/app/application.jar
RUN mkdir /home/app/config-dirs
COPY config-dirs/generateResourcesConfigFile /home/app/config-dirs/generateResourcesConfigFile
RUN native-image -cp /home/app/libs/*.jar:/home/app/resources:/home/app/application.jar --no-fallback -H:Name=application -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk=ALL-UNNAMED -J--add-exports=org.graalvm.nativeimage.builder/com.oracle.svm.core.configure=ALL-UNNAMED -H:ConfigurationFileDirectories=/home/app/config-dirs/generateResourcesConfigFile -H:Class=ch.onstructive.www.Application
FROM frolvlad/alpine-glibc:alpine-3.12
RUN apk update && apk add libstdc++
COPY --from=graalvm /home/app/application /app/application
ENTRYPOINT ["/app/application"] The build folder contains the following content. The micronaut-email.jar and the micronaut-email-mailjet.jar are present. ➜ backend git:(main) tree build/docker/native-main
build/docker/native-main
├── DockerfileNative
├── config-dirs
│ └── generateResourcesConfigFile
│ └── resource-config.json
└── layers
├── application.jar
├── classes
├── libs
│ ├── annotations-13.0.jar
│ ├── gson-2.9.0.jar
│ ├── jackson-annotations-2.13.3.jar
│ ├── jackson-core-2.13.3.jar
│ ├── jakarta.annotation-api-2.1.1.jar
│ ├── jakarta.inject-api-2.0.1.jar
│ ├── javax.annotation-api-1.3.2.jar
│ ├── json-20220320.jar
│ ├── kotlin-stdlib-1.6.21.jar
│ ├── kotlin-stdlib-common-1.6.21.jar
│ ├── kotlin-stdlib-jdk7-1.6.21.jar
│ ├── kotlin-stdlib-jdk8-1.6.21.jar
│ ├── logback-classic-1.2.11.jar
│ ├── logback-core-1.2.11.jar
│ ├── mailjet-client-5.2.1.jar
│ ├── micronaut-aop-3.6.3.jar
│ ├── micronaut-buffer-netty-3.6.3.jar
│ ├── micronaut-context-3.6.3.jar
│ ├── micronaut-core-3.6.3.jar
│ ├── micronaut-core-reactive-3.6.3.jar
│ ├── micronaut-email-1.3.2.jar
│ ├── micronaut-email-mailjet-1.3.2.jar
│ ├── micronaut-http-3.6.3.jar
│ ├── micronaut-http-client-3.6.3.jar
│ ├── micronaut-http-client-core-3.6.3.jar
│ ├── micronaut-http-netty-3.6.3.jar
│ ├── micronaut-http-server-3.6.3.jar
│ ├── micronaut-http-server-netty-3.6.3.jar
│ ├── micronaut-inject-3.6.3.jar
│ ├── micronaut-jackson-core-3.6.3.jar
│ ├── micronaut-json-core-3.6.3.jar
│ ├── micronaut-reactor-2.3.1.jar
│ ├── micronaut-router-3.6.3.jar
│ ├── micronaut-runtime-3.6.3.jar
│ ├── micronaut-serde-api-1.3.2.jar
│ ├── micronaut-serde-jackson-1.3.2.jar
│ ├── micronaut-serde-support-1.3.2.jar
│ ├── micronaut-validation-3.6.3.jar
│ ├── micronaut-websocket-3.6.3.jar
│ ├── netty-buffer-4.1.81.Final.jar
│ ├── netty-codec-4.1.81.Final.jar
│ ├── netty-codec-http-4.1.81.Final.jar
│ ├── netty-codec-http2-4.1.81.Final.jar
│ ├── netty-codec-socks-4.1.81.Final.jar
│ ├── netty-common-4.1.81.Final.jar
│ ├── netty-handler-4.1.81.Final.jar
│ ├── netty-handler-proxy-4.1.81.Final.jar
│ ├── netty-resolver-4.1.81.Final.jar
│ ├── netty-transport-4.1.81.Final.jar
│ ├── netty-transport-native-unix-common-4.1.81.Final.jar
│ ├── okhttp-4.10.0.jar
│ ├── okio-jvm-3.0.0.jar
│ ├── reactive-streams-1.0.4.jar
│ ├── reactor-core-3.4.22.jar
│ ├── slf4j-api-1.7.36.jar
│ ├── snakeyaml-1.31.jar
│ └── validation-api-2.0.1.Final.jar
└── resources
├── application.yml
├── git.properties
└── logback.xml
6 directories, 63 files
The auto generated {
"resources" : {
"includes" : [ {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/ch.onstructive.www.$MailController$Definition$Intercepted$Definition$Reference\\E"
}, {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/ch.onstructive.www.$MailController$Definition$Reference\\E"
}, {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/ch.onstructive.www.$WebsiteConfiguration$Intercepted$Definition$Reference\\E"
}, {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.inject.BeanDefinitionReference/ch.onstructive.www.$MailConfiguration$Intercepted$Definition$Reference\\E"
}, {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.core.beans.BeanIntrospectionReference/ch.onstructive.www.$MailConfiguration$IntrospectionRef\\E"
}, {
"pattern" : "\\QMETA-INF/micronaut/io.micronaut.core.beans.BeanIntrospectionReference/ch.onstructive.www.$MailController$MessageRequest$IntrospectionRef\\E"
}, {
"pattern" : "\\QMETA-INF/spring-configuration-metadata.json\\E"
}, {
"pattern" : "\\Qlogback.xml\\E"
}, {
"pattern" : "\\Qapplication.yml\\E"
}, {
"pattern" : "\\Qgit.properties\\E"
} ],
"excludes" : [ ]
},
"bundles" : [ ]
} |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
Just curious, have you tried without Lombok? |
Beta Was this translation helpful? Give feedback.
Just curious, have you tried without Lombok?