quarkus: unable to deserialize GregorianCalendar

Describe the bug

An attempt to deserialize a GregorionCalendar will lead to a Caused by: java.io.StreamCorruptedException: invalid type code: 00

Expected behavior

serialization should be supported for GregorianCalendar.

Actual behavior

2021-09-26 15:45:36,799 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-0) HTTP Request to /hello/ser failed, error id: 7f645550-6c23-487a-9e7f-ea7baf2ea212-1: org.jboss.resteasy.spi.UnhandledException: java.io.StreamCorruptedException: invalid type code: 00
        at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106)
        at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
        at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:135)
        at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:90)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.lang.Thread.run(Thread.java:829)
        at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:567)
        at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
Caused by: java.io.StreamCorruptedException: invalid type code: 00
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1710)
        at java.io.ObjectInputStream.readArray(ObjectInputStream.java:2077)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1667)
        at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2464)
        at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:629)
        at java.util.Calendar.readObject(Calendar.java:3587)
        at java.lang.reflect.Method.invoke(Method.java:566)
        at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:1175)
        at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2325)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2196)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1679)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:493)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:451)
        at org.acme.getting.started.GreetingResource.serdeser(GreetingResource.java:48)
        at org.acme.getting.started.GreetingResource.serstring(GreetingResource.java:31)
        at java.lang.reflect.Method.invoke(Method.java:566)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
        at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
        at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
        at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408)
        at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
        ... 17 more

How to Reproduce?

create a sample application.

Add the following endpoint:

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/ser")
    public String ser() throws IOException, ClassNotFoundException {
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTimeInMillis(new Date().toInstant().toEpochMilli());
        return "calendar:" + serdeser(calendar);
    }

    private String serdeser(Object obj) throws IOException, ClassNotFoundException {
        byte[] bytes = null;

        try (
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos)) {

            oos.writeObject(obj);
            oos.flush();
            bytes = baos.toByteArray();
        }

        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
                ObjectInputStream ois = new ObjectInputStream(bais)) {
            return "" + ois.readObject();
        }
    }

Add the following serialization-config.json in src/main/resources:

[
  {
    "name": "sun.util.calendar.ZoneInfo"
  }
]

Add the following directive:

<quarkus.native.additional-build-args>-H:SerializationConfigurationResources=serialization-config.json</quarkus.native.additional-build-args>

Add the following class:

@RegisterForReflection(serialization = true, targets = { ArrayList.class, String.class,
        Calendar.class, GregorianCalendar.class, TimeZone.class, SimpleTimeZone.class
})
public class ReflectionConfig {
}

Start a new native build.

Launch the application.

Invoke curl http://localhost:8082/hello/ser

The exception is printed in the server console.

Note : the invocation works fine if the application is started in jvm mode:

$ curl http://localhost:8082/hello/ser
calendar:java.util.GregorianCalendar[time=1632671566284,areFieldsSet=true,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Paris",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=184,lastRule=java.util.SimpleTimeZone[id=Europe/Paris,offset=360
0000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2,minimalDaysInFirstWeek=4,ERA=1,YEAR=2021,MONTH=8,W
EEK_OF_YEAR=38,WEEK_OF_MONTH=4,DAY_OF_MONTH=26,DAY_OF_YEAR=269,DAY_OF_WEEK=1,DAY_OF_WEEK_IN_MONTH=4,AM_PM=1,HOUR=5,HOUR_OF_DAY=17,MINUTE=52,SECOND=46,MILLISECOND=284,ZONE_OFFSET=3600000,DST_OFFSET=3600000]

Output of uname -a or ver

No response

Output of java -version

No response

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.3.0.CR1

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

/cc @zakkak @jaikiran

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 22 (22 by maintainers)

Most upvoted comments

I was able to easily reproduce this even directly with the native-image and a trivial (non-Quarkus) Java application. So this looks like a bug in native-image itself. I’ll report it in the graal repo with a reproducer for their inputs.

I think you should probably adapt ReflectiveHierarchyBuildItem. It mostly does what you want but would need to be adapted for serialization. It doesn’t handle exceptions though.