Skip to content

Rare exception during POJO serialization #764

@huguesb

Description

@huguesb

We're seeing what appears to be some sort of concurrency-related bug in our CI system. It occurs very rarely and only when multiple threads are serializing similar objects.

java.lang.IllegalStateException: null
    at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:890) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89) ~[gson-2.2.4.jar:na]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:195) ~[gson-2.2.4.jar:na]
    at com.google.gson.Gson.toJson(Gson.java:593) ~[gson-2.2.4.jar:na]

The hierarchy being serialized is as follows:

public class ChildrenList {
    public final @Nullable String parent;
    public final List<Folder> folders;
    public final List<File> files;
}

public class CommonMetadata {
    public final String id;
    public final String name;
    public final @Nullable String parent;
    public final @Nullable ParentPath path;
}

public class Folder extends CommonMetadata
{
    public final boolean is_shared;
    public final @Nullable String sid;
    public final @Nullable ChildrenList children;
}

A ChildrenList object is being serialized and dumping the content of the output buffer shows that the error happens in a field of the first Folder element of the folders field. To be precise, the partial output looks like:

{"parent":"8c32f02fed08392bccf015ee0b6274d300000000000000000000000000000000","folders":[{"is_shared":false

A single static Gson instance is shared by multiple threads serializing POJO into HTTP response bodies and is initialized as follows:

    private static final Gson _gson = new GsonBuilder()
            .registerTypeAdapter(Date.class, new DateTypeAdapter())
            .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
            .create();

    /**
     * Enforce ISO 8601 format and UTC timezone for date serialization
     */
    public static class DateTypeAdapter implements JsonSerializer<Date>
    {
        // DateFormat is not thread-safe
        private final ThreadLocal<DateFormat> dateFormat = new ThreadLocal<>();

        @Override
        public JsonElement serialize(Date date, Type type,
                JsonSerializationContext jsonSerializationContext) {
            DateFormat fmt = dateFormat.get();
            if (fmt == null) {
                fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
                fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
                dateFormat.set(fmt);
            }
            String dateFormatAsString = fmt.format(date);
            return new JsonPrimitive(dateFormatAsString);
        }
    }

Has anyone ever run into a similar issue? Is there anything we can do to get a more helpful stack trace when the error happens?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions