Description
PR #3960 introduced LambdaGetterJsonAccessor.create(getter) and LambdaSetterJsonAccessor.create(setter) which use LambdaMetafactory to create lambda classes at runtime. This works fine for JVM execution, but fails in GraalVM Native Image builds because Native Image compilation does not allow classes to be defined at runtime by default.
Error
```
com.oracle.svm.core.jdk.UnsupportedFeatureError: Classes cannot be defined at runtime by default when using ahead-of-time Native Image compilation. Tried to define class io/quarkiverse/fory/it/Bar93972LambdawYqQGiABlx4ie47aSPUZJB
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.generateInnerClass(InnerClassLambdaMetafactory.java:358)
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:282)
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:214)
at java.base@25.0.4.1/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:354)
at org.apache.fory.platform.internal._JDKAccess.makeGetterFunction(_JDKAccess.java:307)
at org.apache.fory.json.meta.JsonFieldAccessor$LambdaGetterJsonAccessor.create(JsonFieldAccessor.java:544)
...
```
Affected Component
java/fory-json/src/main/java/org/apache/fory/json/meta/JsonFieldAccessor.java
The issue affects both:
newGetterAccessor() method (line ~202)
newSetterAccessor() method (line ~209)
Reproduction
This failure is reproduced in quarkus-fory integration tests:
Suggested Fix
Add GraalvmSupport.isGraalBuildTime() check to both newGetterAccessor() and newSetterAccessor() to ensure lambda classes are only created during GraalVM build time (via the Native Image Feature), not at runtime:
```java
private static JsonFieldAccessor newGetterAccessor(Member member) {
Method getter = (Method) member;
return GraalvmSupport.isGraalBuildTime() && USE_JDK25_NATIVE_ACCESS
? LambdaGetterJsonAccessor.create(getter)
: new GetterJsonAccessor(getter);
}
private static JsonFieldAccessor newSetterAccessor(Member member) {
Method setter = (Method) member;
return GraalvmSupport.isGraalBuildTime() && USE_JDK25_NATIVE_ACCESS && setter.getParameterCount() == 1
? LambdaSetterJsonAccessor.create(setter)
: new SetterJsonAccessor(setter);
}
```
See discussion in PR #3960: #3960 (comment)
Description
PR #3960 introduced
LambdaGetterJsonAccessor.create(getter)andLambdaSetterJsonAccessor.create(setter)which useLambdaMetafactoryto create lambda classes at runtime. This works fine for JVM execution, but fails in GraalVM Native Image builds because Native Image compilation does not allow classes to be defined at runtime by default.Error
```
com.oracle.svm.core.jdk.UnsupportedFeatureError: Classes cannot be defined at runtime by default when using ahead-of-time Native Image compilation. Tried to define class io/quarkiverse/fory/it/Bar93972LambdawYqQGiABlx4ie47aSPUZJB
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.generateInnerClass(InnerClassLambdaMetafactory.java:358)
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.spinInnerClass(InnerClassLambdaMetafactory.java:282)
at java.base@25.0.4.1/java.lang.invoke.InnerClassLambdaMetafactory.buildCallSite(InnerClassLambdaMetafactory.java:214)
at java.base@25.0.4.1/java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:354)
at org.apache.fory.platform.internal._JDKAccess.makeGetterFunction(_JDKAccess.java:307)
at org.apache.fory.json.meta.JsonFieldAccessor$LambdaGetterJsonAccessor.create(JsonFieldAccessor.java:544)
...
```
Affected Component
java/fory-json/src/main/java/org/apache/fory/json/meta/JsonFieldAccessor.javaThe issue affects both:
newGetterAccessor()method (line ~202)newSetterAccessor()method (line ~209)Reproduction
This failure is reproduced in quarkus-fory integration tests:
Suggested Fix
Add
GraalvmSupport.isGraalBuildTime()check to bothnewGetterAccessor()andnewSetterAccessor()to ensure lambda classes are only created during GraalVM build time (via the Native Image Feature), not at runtime:```java
private static JsonFieldAccessor newGetterAccessor(Member member) {
Method getter = (Method) member;
return GraalvmSupport.isGraalBuildTime() && USE_JDK25_NATIVE_ACCESS
? LambdaGetterJsonAccessor.create(getter)
: new GetterJsonAccessor(getter);
}
private static JsonFieldAccessor newSetterAccessor(Member member) {
Method setter = (Method) member;
return GraalvmSupport.isGraalBuildTime() && USE_JDK25_NATIVE_ACCESS && setter.getParameterCount() == 1
? LambdaSetterJsonAccessor.create(setter)
: new SetterJsonAccessor(setter);
}
```
See discussion in PR #3960: #3960 (comment)