2

I have an Event class that defines a private HashMap like this:

private Map<String, Object> data = new HashMap<String, Object>();

The Event class is a wrapped for any kind of "event". This HashMap can contain any object instance which is referenced by a key. The class receiving an Event instance knows what class is related to each key, so it can safely cast the Object to its corresponding subclass.

The problem arises when I try to pass an Event instance between 2 processes. Event implements Parcelable so it can be sent through a Message:

Bundle bundle = new Bundle();
bundle.putParcelable(Event.BUNDLE_KEY, event);

// Make the message with the bundle
Message message = new Message();
message.setData(bundle);

When unmarshalling:

public void readFromParcel(Parcel in) {

    idEvent = in.readInt();
    priority = in.readInt();
    idSource = in.readInt();
    idDestination = in.readInt();
    action = in.readInt();

    Bundle mapBundle = in.readBundle();

    if (mapBundle.getSerializable(MAP_KEY) instanceof HashMap) {
        data = (Map<String, Object>) mapBundle.getSerializable(MAP_KEY);
    } else {
        Log.e(TAG, "Parcel reading error: not a HashMap");
    }
}

The problem is this won't work since I need to specify to mapBundle which ClassLoader to use, e.g. mapBundle.setClassLoader(Entity.class.getClassLoader());. But I don't know what Object subclasses the HashMap will have...

This is what I thought:

  • Write a ClassLoader that loads any of these classes. The problem is that I cannot get a way to obtain the byte[] representing the object since it's inside the HashMap. And I cannot use mapBundle.getSerializable() to get it because it precisely throws ClassNotFound exception.

  • Pass some extra information so I can know what classes are on the HashMap. Besides this looking as redundant information, still no go because if I set one classloader on the Bundle, it will still throw a ClassNotFound exception on the other classes...

I would really appreciate some help on this issue. Thanks in advance!

m0skit0
  • 25,268
  • 11
  • 79
  • 127

2 Answers2

1

Actually this answers my question. I have to get a reference to my ClassLoader and then set it up on de-serialization, which I think it's done through another thread, probably a system thread, and thus it doesn't know about my classes.

Community
  • 1
  • 1
m0skit0
  • 25,268
  • 11
  • 79
  • 127
0

I think the best solution is to rethink your plan to have a hashmap of objects and casting them to real objects depending on the key in the hashmap.

By doing that you will not really utilize the typesafety that java provides for you, and you will also get extra overhead from the HashMap.

I would instead recommend to implement the Event as a interface, and have each type of Event implement that interface.

That way the "data" variable in the classes can be renamed with a descriptive name (that makes the code easier to read), and you don't have to store any redundant data.

Alexander Kjäll
  • 4,246
  • 3
  • 33
  • 57
  • Hmmm... Keep in mind that each Event can have several totally different attributes. Also this means a need to implement Parcelable on each of those events. Also this means that if new events are designed later (which is very probable), I have to create such classes, which would make backwards-compatibility totally broken. Also I see no better name than `data` since that's what it is: unknown data. `Event` class does not care about what's in there. – m0skit0 Jul 16 '12 at 12:21
  • Maybe you can write a wrapper that looks at a Parcel before deciding to unpack it or not, and if it gets a Parcel with an idEvent that it don't have in some sort of lookup table, that it discards that Parcel? – Alexander Kjäll Jul 16 '12 at 12:29
  • Deciding to unpack it or not? Why would I sent something I don't want to unpack? Sorry I'm not following you here... The problem is that the HashMap itself is a Serializable, and when I want to get it, it throws a ClassNotFound exception, so I cannot even get the Parcel I want... – m0skit0 Jul 16 '12 at 12:35
  • Sorry for beeing unclear, I meant that if a newer version of the program sends something to an older version, then the older version doesn't know how to handle that event, and need to ignore it. – Alexander Kjäll Jul 16 '12 at 13:27
  • But then it's not as simple with your method. For example a new event will require a new class, but that class is not available on older versions. How would the program know if the problem is loading the class or the class actually doesn't exist? – m0skit0 Jul 16 '12 at 13:32
  • The comment field isn't really the right place to talk about all serilization issues that might arise, but i can point you towards something to read: http://stackoverflow.com/questions/1809670/how-to-implement-serialization-in-c and maybe http://java.sys-con.com/node/36635 – Alexander Kjäll Jul 16 '12 at 13:45
  • Looks like we don't understand each other. The problem is not serialization/de-serialization. This is done successfully. I'm looking for a method to solve my problem, which is to know what ClassLoader to use. – m0skit0 Jul 16 '12 at 13:52
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/13945/discussion-between-alexander-kjall-and-m0skit0) – Alexander Kjäll Jul 16 '12 at 14:21