When we serialize objects, static members are not serialized, but if we need to do so, is there any way out?
Yes, we can serialize the static variables. But we can write our own writeObject()
and readObject()
. I think this can solve the problem.
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~
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.