Skip to content

[Native Image] java.time.Instant Serialization and Deserialization fail in ClassNotFoundException with java.time.Ser #12975

@k6leung

Description

@k6leung

Describe the Issue

Working on a Spring Authorization Server and Spring Session Data Redis project, at login, the following exception is thrown under native image because Spring Session was trying to write java.time.Instant to Redis but failed with the following stacktrace in the docker container (NOTE: I also tried to manually edit the reachability-metadata.json by manually adding the said type
Image
):

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:112) ~[na:na] at org.springframework.data.redis.core.AbstractOperations.deserializeHashValue(AbstractOperations.java:447) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.data.redis.core.AbstractOperations.deserializeHashMap(AbstractOperations.java:391) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.data.redis.core.DefaultHashOperations.entries(DefaultHashOperations.java:386) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at java.base@25.0.2/java.lang.reflect.Method.invoke(Method.java:565) ~[org.example.mongodbtest.MongodbtestApplication:na] at org.springframework.data.redis.core.BoundOperationsProxyFactory$BoundOperationsMethodInterceptor.doInvoke(BoundOperationsProxyFactory.java:177) ~[na:na] at org.springframework.data.redis.core.BoundOperationsProxyFactory$BoundOperationsMethodInterceptor.invoke(BoundOperationsProxyFactory.java:148) ~[na:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[na:na] at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:69) ~[na:na] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[na:na] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:222) ~[na:na] at jdk.proxy4/jdk.proxy4.$Proxy/sec48ab07.entries(Unknown Source) ~[na:na] at org.springframework.session.data.redis.RedisIndexedSessionRepository.getSession(RedisIndexedSessionRepository.java:531) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.session.data.redis.RedisIndexedSessionRepository.findById(RedisIndexedSessionRepository.java:500) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.session.data.redis.RedisIndexedSessionRepository.findById(RedisIndexedSessionRepository.java:267) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getRequestedSession(SessionRepositoryFilter.java:352) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:286) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:193) ~[org.example.mongodbtest.MongodbtestApplication:4.0.1] at jakarta.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:221) ~[org.example.mongodbtest.MongodbtestApplication:6.1] ... Caused by: org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer? at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:81) ~[na:na] at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:38) ~[na:na] at org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:110) ~[na:na] ... 114 common frames omitted Caused by: java.io.IOException: Failed to deserialize object type at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:74) ~[na:na] at org.springframework.core.serializer.support.DeserializingConverter.convert(DeserializingConverter.java:76) ~[na:na] ... 116 common frames omitted Caused by: java.lang.ClassNotFoundException: java.time.Ser at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:327) ~[na:na] at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:297) ~[na:na] at java.base@25.0.2/java.lang.Class.forName(DynamicHub.java:1708) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.lang.Class.forName(DynamicHub.java:1693) ~[org.example.mongodbtest.MongodbtestApplication:na] at org.springframework.util.ClassUtils.forName(ClassUtils.java:302) ~[na:na] at org.springframework.core.ConfigurableObjectInputStream.resolveClass(ConfigurableObjectInputStream.java:76) ~[na:na] at java.base@25.0.2/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1912) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1785) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2101) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2480) ~[na:na] at java.base@25.0.2/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2327) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2133) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject(ObjectInputStream.java:487) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject(ObjectInputStream.java:445) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.util.ArrayList.readObject(ArrayList.java:982) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.lang.reflect.Method.invoke(Method.java:565) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:976) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2302) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2133) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2480) ~[na:na] at java.base@25.0.2/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2327) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2133) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2480) ~[na:na] at java.base@25.0.2/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2327) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2133) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream$FieldValues.<init>(ObjectInputStream.java:2480) ~[na:na] at java.base@25.0.2/java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2327) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2133) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1620) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject(ObjectInputStream.java:487) ~[org.example.mongodbtest.MongodbtestApplication:na] at java.base@25.0.2/java.io.ObjectInputStream.readObject(ObjectInputStream.java:445) ~[org.example.mongodbtest.MongodbtestApplication:na] at org.springframework.core.serializer.DefaultDeserializer.deserialize(DefaultDeserializer.java:71) ~[na:na] ... 117 common frames omitted

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

openjdk version "25.0.2" 2026-01-20
OpenJDK Runtime Environment GraalVM CE 25.0.2+10.1 (build 25.0.2+10-jvmci-b01)
OpenJDK 64-Bit Server VM GraalVM CE 25.0.2+10.1 (build 25.0.2+10-jvmci-b01, mixed mode, sharing)

Operating System and Version

Windows 11 + WSL (ubuntu)

Troubleshooting Confirmation

Run Command

docker run -p 9000:9000 -v "$(pwd)"/jwttest2.pkcs12:/workspace/jwttest2.pkcs12 --name mongotestAuthorizationServer --env-file mongotest.env -d docker.io/library/mongodbtest:0.0.1-SNAPSHOT

mongotest.env:
KEYSTORE_ALIAS=jwt
KEYSTORE_PASSWORD=changeit
KEYSTORE_PATH=jwttest2.pkcs12
MONGO_CONNECTION_STRING=mongodb://appUser:P3qUejzbMw@mongo1:27017,mongo2:27018,mongo3:27019?replicaSet=myReplicaSet&authSource=app&w=2&wtimeoutMS=5000&readPreference=secondaryPreferred&maxStalenessSeconds=90
MONGODB_AUTHDB=app
MONGODB_HOSTPORT=mongo1:27017,mongo2:27018,mongo3:27019
MONGODB_PASSWORD=P3qUejzbMw
MONGODB_REPLICASET=myReplicaSet
MONGODB_USER=appUser
VALKEY_HOST=host.docker.internal
VALKEY_PORT=6379

Expected Behavior

The native image should be able to serialize the class with java.time.Instant properly

Actual Behavior

Image thrown the said error in description.

Steps to Reproduce

(What I did)

  1. Create a project that uses Spring Security Authorization Server (through spring boot starter oauth2 authorization server 4.0.1) and Spring Session Data Redis (through spring session data redis 4.0.1).
  2. Create a user details and registered client registration
  3. Build the native image through maven spring-boot:build-image-no-fork goal with native profile turned on
  4. Run image
  5. Login

(I think one can do this instead for a quick poc)

  1. Start a Spring boot web project with Spring Session Data Redis
  2. Write a controller endpoint and attempt to store a java.time.Instant object into the session
  3. Build the native image
  4. Run the native image and call the endpoint

Additional Context

No response

Run-Time Log Output and Error Messages

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions