Affects: Spring Framework 3.3.0


When running an application build with mvn -Pnative package spring-boot:process-aot spring-boot:build-image, any DataClassRowMapper for record classes, will throw an exception when they are initialized.

Reproduction: 1. Create a new project using JDBC and Native Image support. 2. Create a record. 3. In the main method, add DataClassRowMapper.newInstance(NameOfRecord.class). 4. Start a JDBC database and configure application.properties. In my case, this was a PostgreSQL container. 5. Build the native image: ./mvnw -Pnative package spring-boot:process-aot spring-boot:build-image 6. Run the image: docker run --net=host --volume ./src/main/resources:/config docker.io/library/native-data-class-row-mapper:0.0.1-SNAPSHOT -Dspring.config.location=/config/application.properties

The application will crash with the following stacktrace:

Exception in thread "main" java.lang.IllegalStateException: No primary or single unique constructor found for class ooo.sansk.nativedataclassrowmapper.NativeDataClassRowMapperApplication$Example
        at org.springframework.beans.BeanUtils.getResolvableConstructor(BeanUtils.java:265)
        at org.springframework.jdbc.core.DataClassRowMapper.initialize(DataClassRowMapper.java:95)
        at org.springframework.jdbc.core.BeanPropertyRowMapper.<init>(BeanPropertyRowMapper.java:138)
        at org.springframework.jdbc.core.DataClassRowMapper.<init>(DataClassRowMapper.java:87)
        at org.springframework.jdbc.core.DataClassRowMapper.newInstance(DataClassRowMapper.java:146)
        at ooo.sansk.nativedataclassrowmapper.NativeDataClassRowMapperApplication.main(NativeDataClassRowMapperApplication.java:10)
        at java.base@21.0.3/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)

A minimal reproduction can be found here: https://github.com/SanderKnauff/spring-boot-repro-native-data-class-row-mapper

Comment From: bclozel

Thanks for this detailed report.

I think this is solved typically by registering reflection for this record class in your application. This reflection cannot be inferred by Spring as this is done in the body of an application method and there is no way for us to detect this usage by looking at the application context.

You can use @RegisterReflectionForBinding(NameOfRecord.class) in a configuration class to register the relevant runtime reflection information for native.

See the reference docs about this.