jackson-modules-base
jackson-modules-base copied to clipboard
Cannot Deserialize Object with Builder when using AfterBurner and UseValueClassLoader is false
Description
When using @JsonDeserialize(builder = ...)
along with @JsonPojoBuilder
, deserialization fails when the Afterburner module is registered with new ObjectMapper().registerModule(new AfterburnerModule().setUseValueClassLoader(false));
Test cases showing the issue: https://github.com/austinarbor/jackson-afterburner-issue/blob/main/src/test/java/dev/aga/model/ContextTest.java
When setUseValueClassLoader(true)
everything works as expected
class dev.aga.model.Context$ContextBuilder$Creator4JacksonDeserializer8cf3272c tried to access method 'void dev.aga.model.Context$ContextBuilder.<init>()' (dev.aga.model.Context$ContextBuilder$Creator4JacksonDeserializer8cf3272c is in unnamed module of loader com.fasterxml.jackson.module.afterburner.util.MyClassLoader @2f53b467; dev.aga.model.Context$ContextBuilder is in unnamed module of loader 'app')
java.lang.IllegalAccessError: class dev.aga.model.Context$ContextBuilder$Creator4JacksonDeserializer8cf3272c tried to access method 'void dev.aga.model.Context$ContextBuilder.<init>()' (dev.aga.model.Context$ContextBuilder$Creator4JacksonDeserializer8cf3272c is in unnamed module of loader com.fasterxml.jackson.module.afterburner.util.MyClassLoader @2f53b467; dev.aga.model.Context$ContextBuilder is in unnamed module of loader 'app')
at dev.aga.model.Context$ContextBuilder$Creator4JacksonDeserializer8cf3272c.createUsingDefault(dev/aga/model/Context$ContextBuilder$Creator4JacksonDeserializer.java)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.vanillaDeserialize(BuilderBasedDeserializer.java:285)
at com.fasterxml.jackson.databind.deser.BuilderBasedDeserializer.deserialize(BuilderBasedDeserializer.java:217)
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4309)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4245)
at dev.aga.model.ContextTest.testDeserWithAfterburnerAndUseValueClassLoaderFalse(ContextTest.java:42)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
Sounds like issue for Java 9+ Module system (JPMS). Not sure what could be done about that, hoping someone else can comment.
For Lombok users:
I'm experiencing this issue when using @Jacksonized @Builder
.
For some reason, if I change the @Builder
to @SuperBuilder
(I'm not using inheritance, so there is no reason to use @SuperBuilder
) it seems to work but with An illegal reflective access operation has occurred
warning.
One way out of this could be to extend @JsonDeserialize
to support specifying a static builder creation method. In this way, no reflective access to the actual builder class is necessary. Jackson could simply call clazz.getMethod(builderMethod)
.
Reflective access is still needed for the builder method (that's what getMethod()
is), but that might be easier to open via module definitions.
Despite the release of Lombok version 1.18.26, the issue mentioned still persists. However, the workaround suggested by @agargaglione still provides a solution
@Jacksonized
@SuperBuilder
Another workaround (that worked for me), is to switch from Afterburner to Blackbird (if you are on Java 11+).
Also Blackbird seems to be the future anyway...