35

When we serialize objects, static members are not serialized, but if we need to do so, is there any way out?

Carl Manaster
  • 38,312
  • 15
  • 96
  • 147
Maddy.Shik
  • 6,241
  • 15
  • 62
  • 98

9 Answers9

22

The first question is why you need to serialize the static members?

Static members are associated with the class, not the instances, so it does not make sense to include them when serializing an instance.

The first solution is to make those members not static. Or, if those members are the same in the original class and the target class (same class, but possibly different runtime environments), don't serialize them at all.

I have a few thoughts on how one could send across static members, but I first need to see the use case, as in all cases that means updating the target class, and I haven't found a good reason to do so.

Kathy Van Stone
  • 23,459
  • 3
  • 29
  • 40
  • 2
    suppose i want to count number of instance of a class like Car. and i am not using database .so in that case after application shutdown i need to store this information with other information. – Maddy.Shik Jun 18 '09 at 05:11
  • 4
    Do you need to store that number directly? If you update the number as you deserialize each Car (by overriding readObject) it will correctly reflect the numbr of cars in the serialization. – Kathy Van Stone Jun 18 '09 at 12:27
  • Static variable are shared between all instances of a class's objects (shared memory). If you need to save something static, like lets you had an enum of different values and from time to time you'd change a static value of that enum type, changing the saved value could be as simple as having all classes set a local variable to that type. Or you could take it a step further, and have a bunch of classes extend class Whatever, and class Whatever could just share a local variable to all its children. The when you deserialize you can reload your static values back to how they were. –  Nov 23 '12 at 05:32
20

Folks, static doesn't mean IMMUTABLE. For instance, I may want to serialize the whole state of the computation (yes, including static fields -- counters, etc) to resume later, after JVM and/or host computer restarted.

The right answer to that, as already said, is to use Externalizable, not Serializable, interface. Then you have a complete control on what and how you externalize.

Vladimir Dyuzhev
  • 17,603
  • 9
  • 45
  • 61
  • 1
    If the state of the computation isn't embedded in the object you are serializing then you shouldn't be storing it as part of serialization of that object. – DJClayworth Jun 17 '09 at 16:57
  • 3
    Mutable static generally means broken. – Tom Hawtin - tackline Jun 17 '09 at 17:36
  • 2
    Think again. How about multithreaded genetic algorithms, for instance? Shared (static) storage is used to keep the registry of evaluated variants. Make it a singleton? Possible, but it has own drawbacks. – Vladimir Dyuzhev Jun 17 '09 at 18:31
  • 3
    Yes. Make it a singleton. Serialize the singleton. Or, better, get rid of shared static storage, store it in an explicit context object. – Thilo Jun 18 '09 at 11:08
  • 2
    ... And then another bunch of purist will complain that Singleton is anti-pattern I should get rid of it too. As for "explicit context object", how do different threads access it? Via static methods? How's it better? – Vladimir Dyuzhev Jun 18 '09 at 15:05
  • By "explicit" context object I meant passing it around explicitly to everyone who needs it. – Thilo Jun 19 '09 at 04:00
7

This is serialization for the static field: newBookingNumber.

class Booking implements Serializable
{

    /**
     * Generated serial version ID.
     */

    private static final long serialVersionUID = 5316748056989930874L;

    // To hold new booking number.
    private static int newBookingNumber = 0;

    // The booking number.
    private int bookingNumber;


    /* 
     * Default serializable fields of a class are defined to be 
     * the non-transient and non-static fields. So, we have to 
     * write and read the static field separately.
     */
    private void writeObject(ObjectOutputStream oos)
        throws IOException 
    {
        oos.defaultWriteObject();
        oos.writeObject(new Integer(newBookingNumber));
    }

    private void readObject(ObjectInputStream ois)
    throws ClassNotFoundException, IOException 
    {
        ois.defaultReadObject();
        newBookingNumber = (Integer)ois.readObject();
    }
}
Peter O.
  • 28,965
  • 14
  • 72
  • 87
Adam
  • 71
  • 1
  • 1
5

You can control serialization by implementing:

private void writeObject(ObjectOutputStream out) throws IOException;

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;

There's a full description of serialization http://java.sun.com/developer/technicalArticles/Programming/serialization/.

As other answers have said, it doesn't really make sense to serialize statics as it's the object not the class you're serializing and needing to do so smells like you've got other issues with your code to me.

Nick Holt
  • 31,429
  • 4
  • 46
  • 56
  • 1
    You can control serialisation, but that there is nowhere sensible to put static data because it doesn't make any sense in the context. – Tom Hawtin - tackline Jun 17 '09 at 17:38
  • 1
    Since we don't know the context, we can't say whether it makes sense or not. For example, after using the default serialization, it might make sense to add the static member to the stream. At deserialization, one can set the static member if it is null, otherwise discard the serialized object. – erickson Jun 17 '09 at 18:08
  • 1
    Tom, you're abusing "proof by repetition", don't you? ;) – Vladimir Dyuzhev Jun 17 '09 at 18:38
  • is there any wayout to serialize static members by serializing Class Object fr my class. – Maddy.Shik Jun 18 '09 at 05:16
2

Good answers and comments--don't do it. But how?

Chances are you would be best off creating an object to hold all your "Statics". That object should probably have any static methods from your class as well.

Every instance of your class can hold this other class--or if you really have to you can make it a singleton that any member can access.

After you do this refactor, you will find that it should have been done this way all along. You may even find that some of your previous design constraints that were bothering you at a subconsicionce level have vanished.

You'll probably find that this solution also solves other Serialization problems you hadn't even noticed yet.

Bill K
  • 60,031
  • 14
  • 96
  • 147
2

You can do this without having to manually update your class every time you simply change a field. You may want to do this if you want to have the ease of static members for access to settings in an application, but would also like to save those settings. In this case, you would also want to have the option to apply them at whim, not load by default as the other solutions here necessitate, since they are static. This allows for rollback of settings for obvious reasons.

Basically, use the field methods to get all the members in the class, then map the full names of these fields to the contents. The full name is required since Field is not serializable itself. Serialize this mapping, and reinstate it to get the saved settings.

The second part of the puzzle is the apply() type of function. This goes thru the mapping, and applies what it can to the static class.

You must also ensure that the contents of the static members are themselves serializable.

As can hopefully be seen from this example class, the static members can easily be saved and returned. I'll leave it up to the implementer to worry about UIDs of classes, safeguards etc. isSameAs() is used for unit testing. AppSettings is the class that contains all the static fields that you wish to serialize.

public class AppSettingsReflectorSaver implements Serializable {

HashMap<String, Object> genericNamesAndContents = new HashMap<String, Object>();
private AppSettingsReflectorSaver() {
}

static AppSettingsReflectorSaver createAppSettingsSaver() {
    AppSettingsReflectorSaver ret = new AppSettingsReflectorSaver();
    ret.copyAppSettings();
    return ret;
}

private void copyAppSettings() {
    Field[] fields = AppSettings.class.getFields();
    for (Field field : fields) {
        mapContentsForSerialization(field);
    }
}

private void mapContentsForSerialization(Field field) {
    try {
        Object fieldContents = field.get(AppSettings.class);
        genericNamesAndContents.put(field.toGenericString(), fieldContents);
    } catch (IllegalArgumentException ex) {
        Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
    }
}

boolean isSameAs(AppSettingsReflectorSaver now) {
    for( String thisKey : genericNamesAndContents.keySet()){
        boolean otherHasThisKey = now.genericNamesAndContents.containsKey(thisKey);
        Object thisObject = genericNamesAndContents.get(thisKey);
        Object otherObject = now.genericNamesAndContents.get(thisKey);
        boolean otherHasThisValue = thisObject.equals(otherObject);
        if (!otherHasThisKey || !otherHasThisValue){
            return false;
        }
    }
    return true;
}

void applySavedSettingsToStatic() {
    Field[] fields = AppSettings.class.getFields();
    for (Field field : fields) {
        if (!genericNamesAndContents.containsKey(field.toGenericString())){
            continue;
        }
        Object content = genericNamesAndContents.get(field.toGenericString() );
        try {
            field.set(AppSettings.class, content);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

}

This is my first post - go easy on me :P~

bobjandal
  • 2,013
  • 2
  • 13
  • 8
1

Static members belong to the class, not to the individual objects.

You should reconsider your data structure.

Thorbjørn Ravn Andersen
  • 68,906
  • 28
  • 171
  • 323
0

Yes, we can serialize the static variables. But we can write our own writeObject() and readObject(). I think this can solve the problem.

cosmin
  • 20,422
  • 5
  • 39
  • 57
naresh
  • 11
0

To have compact implementation, implement readObject & writeObject in your class call defaultReadObject & defaultWriteObject methods within those methods which handles normal serialization and then proceed with serializing & de-serializing whatever additional fields you need.

Regards, GK

G Kumar
  • 131
  • 1
  • 2