I've run into an issue with the jakarta.persistence.Convert annotation with GraalVM and Spring Native, see the stacktrace below.

I'm a bit unsure if this issue should be reported here, with the Hibernate project or elsewhere .

Could not resolve matching constructor on bean class [.....EmailConverter] (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1751) ~[demo:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[demo:6.0.3]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[demo:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[demo:6.0.3]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[demo:6.0.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[demo:6.0.3]

The Converter is implemented as shown below and is applied via @Convert(converter = ....). The issue does not present itself if I remove the @Convert and instead auto apply it via @Converter(autoApply = true).

@Column(name = "email", columnDefinition = "varchar(255) not null", nullable = false)
@Convert(converter = EmailConverter.class)
@NaturalId
private Email email;
public final class EmailConverter implements AttributeConverter<Email, String> {
    public EmailConverter() {}

    @Override
    public String convertToDatabaseColumn(final Email attribute) {
        return attribute.getValue();
    }

    @Override
    public Email convertToEntityAttribute(final String dbData) {
        return new Email(dbData);
    }

}

You can reproduce the issue with https://github.com/NicklasWallgren/spring-boot-native-issue

Comment From: wilkinsona

Thanks for the sample. Unfortunately, it doesn't compile:

./gradlew nativeCompile  
Starting a Gradle Daemon, 3 incompatible Daemons could not be reused, use --status for details

> Task :compileJava FAILED
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:10: error: cannot find symbol
public final class Email extends ValueObject<String> {
                                 ^
  symbol: class ValueObject
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:30: error: cannot find symbol
        if (value != null) {
            ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:31: error: cannot find symbol
            return value;
                   ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:37: error: method does not override or implement a method from a supertype
    @Override
    ^
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:40: error: cannot find symbol
            throw ValidationErrorException.of(ValidationError.of("invalid email address", value, "email"));
                                                                                          ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:50: error: cannot find symbol
        if (value == null) {
            ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:54: error: cannot find symbol
        final int splitPosition = value.lastIndexOf('@');
                                  ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:59: error: cannot find symbol
        final String localPart = value.substring(0, splitPosition);
                                 ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/Email.java:60: error: cannot find symbol
        final String domainPart = value.substring(splitPosition + 1);
                                  ^
  symbol:   variable value
  location: class Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/EmailConverter.java:19: error: cannot find symbol
        return attribute.getValue();
                        ^
  symbol:   method getValue()
  location: variable attribute of type Email
/Users/awilkinson/dev/temp/spring-boot-native-issue/src/main/java/com/example/demo/EmailConverter.java:26: error: constructor Email in class Email cannot be applied to given types;
        return new Email(dbData);
               ^
  required: String
  found:    String
  reason: Email(String) has private access in Email
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
11 errors

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 13s
1 actionable task: 1 executed

Comment From: NicklasWallgren

@wilkinsona Sorry, I forgot to push the latest changes. It should compile now.

Comment From: wilkinsona

Running the app with debug logging enabled shows that both SpringBeanContainer and Hibernate itself fail to create an instance of EmailConverter:

2023-01-05T13:14:14.868Z DEBUG 50100 --- [       Thread-1] o.s.orm.hibernate5.SpringBeanContainer   : Falling back to Hibernate's default producer after bean creation failure for class com.example.demo.EmailConverter: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.demo.EmailConverter': Could not resolve matching constructor on bean class [com.example.demo.EmailConverter] (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
2023-01-05T13:14:14.868Z DEBUG 50100 --- [       Thread-1] o.s.orm.hibernate5.SpringBeanContainer   : Fallback producer failed for class com.example.demo.EmailConverter: org.hibernate.InstantiationException: Could not instantiate managed bean directly : com.example.demo.EmailConverter

This is due to a lack of reflection hints which means that the converter class cannot be created reflectively in a native image. You could work around the problem by using @ImportRuntimeHints to import a RuntimeHintsRegistrar implementation that registers EmailConverter allowing invocation of its public constructors. We can also look into doing this automatically.

Comment From: NicklasWallgren

@wilkinsona Thanks for the clarification. I will look in to RuntimeHintsRegistrar.

Comment From: wilkinsona

As discussed with @sdeleuze, PersistenceManagedTypesBeanRegistrationAotProcessor looks like a logical place for us to deal with this. We've transferred this to the Framework repository (thanks, Brian!) for their further consideration.

Comment From: wilkinsona

@NicklasWallgren Your sample app starts when this change is applied to its main class:

diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java
index 64b538a..76b9b00 100644
--- a/src/main/java/com/example/demo/DemoApplication.java
+++ b/src/main/java/com/example/demo/DemoApplication.java
@@ -1,13 +1,29 @@
 package com.example.demo;

+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.RuntimeHintsRegistrar;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ImportRuntimeHints;
+
+import com.example.demo.DemoApplication.ConverterRuntimeHints;

 @SpringBootApplication
+@ImportRuntimeHints(ConverterRuntimeHints.class)
 public class DemoApplication {

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

+       static class ConverterRuntimeHints implements RuntimeHintsRegistrar {
+
+               @Override
+               public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+                       hints.reflection().registerType(EmailConverter.class, MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
+               }
+
+       }
+
 }

Comment From: NicklasWallgren

@wilkinsona Great, thanks for the help!