Search code examples
javadockermavenmicronautgraalvm

Micronaut DI does not work with Graal Native Image built in Maven


I have a minimal app on Micronaut it looks like this:

@Introspected
public class BookRequestHandler extends MicronautRequestHandler<Book, BookSaved> {

    @Inject
    private BookService service;

    @Override
    public BookSaved execute(Book input) {
        return service.process(input);
    }

}

@Singleton
@Introspected
public class BookService {

  public BookSaved process(Book input) {
    BookSaved bookSaved = new BookSaved();
    bookSaved.setName(input.getName());
    bookSaved.setIsbn(UUID.randomUUID().toString());
    return bookSaved;
  }

}
  • Runtime and DTO classes.

My project successfully builds and runs on Graal Native Image using a plugin from Micronaut - ./mvnm

But I am trying to use native-image to build directly through Docker container. And the image is going! But if I try to call the lambda, I get an error that the field for dependency injection was not found :( This file is remade from Micronaut's Gradle version:

# STEP 1: Packaging project .jar in Docker image 'builder'
FROM maven:3.6.3-jdk-8 as build

COPY . /home/application
WORKDIR /home/application

RUN mvn clean package

# STEP 2: Downloading Graal and C libraries in Docker image 'graalvm'
FROM amazonlinux:2018.03 as graal

ENV LANG en_US.UTF-8
ENV JDK_VERSION java8
ENV GRAAL_VERSION 21.0.0.2
ENV GRAAL_FILENAME graalvm-ce-${JDK_VERSION}-linux-amd64-${GRAAL_VERSION}.tar.gz

RUN yum install -y gcc gcc-c++ libc6-dev zlib1g-dev curl bash zlib zlib-devel zip
RUN curl -4 -L https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-${GRAAL_VERSION}/${GRAAL_FILENAME} -o /tmp/${GRAAL_FILENAME}
RUN tar -zxvf /tmp/${GRAAL_FILENAME} -C /tmp
RUN mv /tmp/graalvm-ce-${JDK_VERSION}-${GRAAL_VERSION} /usr/lib/graalvm
RUN rm -rf /tmp/*

CMD ["/usr/lib/graalvm/bin/native-image"]

# STEP 3: Building and zipping a Native Image with bootstrap file
FROM graal

COPY --from=build /home/application/ /home/application/
WORKDIR /home/application

RUN /usr/lib/graalvm/bin/gu install native-image
RUN /usr/lib/graalvm/bin/native-image --no-fallback --no-server -jar target/MicronautGraal-0.1.jar -H:Name=micronaut-graal -H:Class=com.example.BookLambdaRuntime
RUN chmod 777 bootstrap
RUN chmod 777 micronaut-graal
RUN zip -j micronaut-graal.zip bootstrap micronaut-graal

EXPOSE 8080
ENTRYPOINT ["/home/application/complete"]

The error itself:

io.micronaut.context.exceptions.DependencyInjectionException: Failed to inject value for field [service] of class: com.example.BookRequestHandler
Message: Error setting field value: No field 'service' found for type: com.example.BookRequestHandler

I'm sure the problem is not in the code, as it will run and work through the ./mvnm plugin. Am I missing something in the app build? My image through the plugin is 500kb more than through native-image directly.

I would really appreciate any help. Thanks!


Solution

  • The problem went away after adding the annotation processor path - graal, and explicitly declaring validation and inject in the inheritor:

    <annotationProcessorPaths>
      <path>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-graal</artifactId>
        <version>${micronaut.version}</version>
      </path>
      <path>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-inject-java</artifactId>
        <version>${micronaut.version}</version>
      </path>
      <path>
        <groupId>io.micronaut</groupId>
        <artifactId>micronaut-validation</artifactId>
        <version>${micronaut.version}</version>
      </path>
    </annotationProcessorPaths>