Birger Birger - 2 months ago 8
Java Question

My serializers depend on each other, how can I ensure both are used

Imagine I have two classes,

MyClass
and
MyOtherClass
. I've written a serializer for
MyClass
. Without it, trying to serialize
MyOtherClass
won't work (because
MyClass
isn't serializable without the serializer I've written).

package com.mycompany.javatest;

import com.google.gson.*;
import java.lang.reflect.*;

public class JavaTest {

static class MyClass {

private int someValue = 123;
}

static class MyOtherClass {

private MyClass mc = new MyClass();
}

static class MyClassSerializer implements JsonSerializer<MyClass> {

@Override
public JsonElement serialize(MyClass t, Type type, JsonSerializationContext jsc) {

JsonObject result = new JsonObject();
// (Doing some magic to serialize the object here...)
result.add("someValue", jsc.serialize(t.someValue));
return result;

}
}

static class MyOtherClassSerializer implements JsonSerializer<MyOtherClass> {

@Override
public JsonElement serialize(MyOtherClass t, Type type, JsonSerializationContext jsc) {

JsonObject result = new JsonObject();
result.add("mc", jsc.serialize(t.mc)); // <--- Will fail if not using the MyClassSerializer
return result;

}
}

public static void main(String[] args) {

GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(MyOtherClassSerializer.class, new MyOtherClassSerializer());
Gson gson = gb.create();
MyOtherClass object = new MyOtherClass();

String json = gson.toJson(object, MyOtherClass.class); // <--- MyClassSerializer.serialize MUST be invoked, or this will fail

}
}


My question is, how can I enforce that
MyClassSerializer
is registered when
MyOtherClassSerializer
is registered? The obvious answer is to just register both type adapters, but I'd like to know if there is a way to enforce registering both when registering
MyOtherClassSerializer
. One option is to only allow the type adapters to be accessed by a "register" method like this, but I don't like this solution. I still want the
MyClassSerializer
to be accessible.

public void registerMyOtherClassSerializer(GsonBuilder builder) {

builder.registerTypeAdapter(MyClass.class, new MyClassSerializer());
builder.registerTypeAdapter(MyOtherClass.class, new MyOtherClassSerializer());

}


Thoughts?

Answer

Thanks to Thomas Kl├Ąger. This is what I ended up doing:

package com.mycompany.javatest;

import com.google.gson.*;
import com.google.gson.reflect.*;
import com.google.gson.stream.*;
import java.io.*;

public class JavaTest {

    static class MyClass {
        private final int someValue = 123;
    }

    static class MyOtherClass {
        private final MyClass mc = new MyClass();
    }

    public static void main(String[] args) {

        GsonBuilder gb = new GsonBuilder();
        gb.registerTypeAdapterFactory(new MyTypeAdapterFactory());
        Gson gson = gb.create();
        MyOtherClass object = new MyOtherClass();

        String json = gson.toJson(object, MyOtherClass.class);
        System.out.println(json);

    }

    static class MyTypeAdapterFactory implements TypeAdapterFactory {

        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> tt) {

            if (MyClass.class.isAssignableFrom(tt.getRawType())) {
                return (TypeAdapter<T>) new MyClassAdapter();
            }

            return null;
        }

        private static class MyClassAdapter extends TypeAdapter<MyClass> {

            @Override
            public MyClass read(JsonReader reader) throws IOException {
                throw new UnsupportedOperationException();
            }

            @Override
            public void write(JsonWriter writer, MyClass t) throws IOException {
                writer.beginObject();
                writer.name("someValue");
                writer.value(t.someValue); // (Doing some magic to serialize the object here...)
                writer.endObject();
            }
        }
    }
}