2

I'm using Square's Tape library and i've run in to a requirement where i basically need to have an abstract TapeTask class. The problem though is that the deserialization process for the GsonConverter (which implements the library's FileObjectQueue.Converter - as demonstrated in the sample project) doesn't play well with interfaces/abstract classes.

I thought it was a Gson deserialization problem so i registered my Gson instance with a custom TypeAdapter, but that still doesn't do the trick. I figure it has something to do with the FileObjectQueue.Converter.

I'm currently trying to work around this problem, with a nasty wrapper callback interface from my sub-tasks.

My requirement is to have a single TapeQueue and be able to send in multiple types of tasks. So I have a TapeTask abstract class and have concrete implementations like ImageDownloadTask, ImageUploadTask, UrlPostWithRetrofitTask, GoogleAnalyticsTrackerTask ... etc. all going in to a single queue.

Is there a way to achieve this. I guess my question boils down to: What do i need to do to make the FileObjectQueue.Converter play well with abstract classes?

hint :P : The javadoc for that class says "..you need to also include the concrete class name in the serialized byte array" but i'm not sure what that means. If anyone could post an explanation of how the name can be included in the serialized byte array, in a way that achieves my purpose, i'd be grateful!

KG -
  • 7,130
  • 12
  • 56
  • 72

1 Answers1

2

I went ahead and wrote an Abstract Gson Convertor. I don't think it's super-efficient but gets the job done:

/**
 * Use GSON to serialize classes to a bytes.
 *
 * This variant of {@link GsonConverter} works with anything you throw at it.
 * It is however important for Gson to be able to understand your inner complex objects/entities
 * Use an {@link InterfaceAdapter} for these purposes.
 *
 */
public class GsonAbstractClassConverter<T>
    implements FileObjectQueue.Converter<T> {

    public static final String CONCRETE_CLASS_NAME = "concrete_class_name";
    public static final String CONCRETE_CLASS_OBJECT = "concrete_class_object";
    private final Gson _gson;

    public GsonAbstractClassConverter(Gson gson) {
        _gson = gson;
    }

    @Override
    public T from(byte[] bytes) {
        Reader reader = new InputStreamReader(new ByteArrayInputStream(bytes));
        JsonObject completeAbstractClassInfoAsJson = _gson.fromJson(reader, JsonObject.class);

        Class<T> clazz;
        try {
            String className = completeAbstractClassInfoAsJson.get(CONCRETE_CLASS_NAME).getAsString();
            clazz = (Class<T>) Class.forName(className);
        } catch (ClassNotFoundException e) {
            Timber.e(e, "Error while deserializing TapeTask to a concrete class");
            return null;
        }

        String objectDataAsString = completeAbstractClassInfoAsJson.get(CONCRETE_CLASS_OBJECT)
                                                                   .getAsString();

        return _gson.fromJson(objectDataAsString, clazz);
    }

    @Override
    public void toStream(T object, OutputStream bytes) throws IOException {
        Writer writer = new OutputStreamWriter(bytes);

        JsonObject completeAbstractClassInfoAsJson = new JsonObject();
        completeAbstractClassInfoAsJson.addProperty(CONCRETE_CLASS_NAME, object.getClass().getName());
        completeAbstractClassInfoAsJson.addProperty(CONCRETE_CLASS_OBJECT, _gson.toJson(object));

        _gson.toJson(completeAbstractClassInfoAsJson, writer);
        writer.close();
    }
}
KG -
  • 7,130
  • 12
  • 56
  • 72
  • Whenever I try to peek a task using this code I get a NPE on "completeAbstractClassInfoAsJson.get(CONCRETE_CLASS_NAME).getAsString();" any idea why? – bestdayever Oct 06 '14 at 15:36
  • Probably because ur json parsing is failing? Hope u noticed the caveat on using interface adapters if you have complex entities. I would first suggest trying to make sure you can covert to and from json. If you're able to do that then your problem should go away – KG - Oct 07 '14 at 15:47