简体   繁体   中英

Spring Boot 3 Native with lombok immutable (@Value)

I've been trying to create a example project using spring boot 3, graalvm, lombok and jpa. Everything looks perfect when I execute the test using the main method. But I have a problem when I run the native binary.

First I create the binary:

mvn -Pnative native:build

Then I run the project:

./target/demo

The project start fine, but when I try to create a new record using curl:

curl --location --request POST 'localhost:8080' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "test",
    "surname": "surname"
}'

I see this error in console:

2022-12-21T01:51:48.055+01:00  WARN 105751 --- [nio-8080-exec-2] .c.j.MappingJackson2HttpMessageConverter : Failed to evaluate Jackson deserialization for type [[simple type, class com.example.demo.dto.ExampleDto]]: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Builder class `com.example.demo.dto.ExampleDto$ExampleDtoBuilder` does not have build method (name: 'build')
2022-12-21T01:51:48.055+01:00  WARN 105751 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/json;charset=UTF-8' is not supported]

My DTO looks like this:

@Value
@Builder
@Jacksonized
public class ExampleDto {
    Integer id;
    String name;
    String surname;

}

The controller:

@RestController
@RequestMapping("/")
@AllArgsConstructor
@Slf4j
public class ExampleController {

    private final ExampleService exampleService;

    @GetMapping
    public ExampleDto findByName(@RequestParam String name) {
        return exampleService.getByName(name);
    }

    @PostMapping
    public void save(@RequestBody ExampleDto dto) {
        exampleService.save(dto);
    }
}

The problem is pretty clear, there is a problem with the "build" method that is created by lombok. If I inspect the generated source I can see the method in the right place. Apparently GraalVM (or jackson) does not see the method.

I also tried to add some traces in a GET method just to be sure that the controller has access to to builder.build() method and the method exist in runtime. (2nd clue that gives me the idea that there is a configuration problem.

I removed the @Value , @Jacksonized and @Builder and put just @Data and everything works fine.

Any idea? Should I add an extra configuration?

The example project is in github: https://github.com/elysrivero99/spring-boot-3-native-demo

After a while I found the answer. You have to add the hints as:

@SpringBootApplication
@ImportRuntimeHints(DemoApplication.DemoApplicationRuntimeHints.class)
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    static class DemoApplicationRuntimeHints implements RuntimeHintsRegistrar {

        @SneakyThrows
        @Override
        public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
            hints.reflection()
                    .registerConstructor(ExampleDto.ExampleDtoBuilder.class.getDeclaredConstructor(), ExecutableMode.INVOKE)
                    .registerMethod(
                            ExampleDto.ExampleDtoBuilder.class.getMethod("build"), ExecutableMode.INVOKE);
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM