Java: Serialization: How to store only a reference, not the content - java

I'm creating an undo-redo mechanism. To achieve this, I'm using Serialization. Recording the current state by writing it to a ByteArrayOutputStream, using ObjectOutputStream and putting the byte[] into an ArrayList.
But the problem is that, some of the classes are holding a reference/pointer to a BufferedImage. Which I don't want to serialize because of its size (and it doesn't implement Serializable). The reason why I don't want to write it is that it will never change. But it is a different image for each instance of the class, so the static keyword isn't a solution.
My attempt to solve:
public transient BufferedImage img;
This causes the ObjectOutputStream will not serialize the BufferedImage, but it won't store the reference as well. After deserializing, it will be null.
So, in short, I want to keep the reference to the object, but not the object itself. Which means that, after deserialazing I will be able to use the BufferedImage (because of it isn't removed by the Garbage Collector).
Many thanks.

OK, simple enough, keep a Map<String, BufferedImage> of all images somewhere in your application, let each of your classes serialize the key to its image. And in the readResolve() method, look up the image from the map.

What you are asking for is impossible. Think about it...if you serialized your object and sent it over the internet to a different computer, how on earth would that BufferedImage reference end up pointing to the right object without you sending over the BufferedImage itself as well?
It seems like you're serializing and deserializing within the same Java instance. That's certainly not what Java serialization is meant for; the general case is that the instance that serializes an object will not be the same as the one that deserializes it.
What you can do is write custom (de)serialization logic for your class via readObject() and writeObject(). You could for instance serialize the resource URL or a unique identifier for the image instead of the image itself.

You could add writeObject(java.io.ObjectOutputStream stream) and readObject(java.io.ObjectInputStream stream) methods to your object to customize the serialization process.
Mark the reference transient and then perform logic in writeObject to write a token in the stream to let you identify it later in readObject and re-create it.
See this page for an example of this:
http://www.javapractices.com/topic/TopicAction.do?Id=70

In short you can't with only serialization. So I'd suggest getting clever with it. Still continue to mark it transient, but you can hook the serialization process to write out the image when you save it. By adding a methods:
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException
Those will get called when you deserialize and serialize (respectively). You could then save the file's contents out to a temp folder. Using some sort of unique ID for each instance you could keep separate files on the filesystem so when you undo/redo you would read and write to the same file no matter how many levels of undo/redo you have.
Remember to call defaultWriteObject() and defaultReadObject() inside those methods you're adding so the default serialization is performed.

Related

Java: Save Object for Later Use

Pulling the data from the server (using SOAP methods) is slow and I would like that the program loads with the object already present. I tried the code I found here, but it raises a java.io.NotSerializableException
Now I need the data to remain intact. Is there any way to save it without modifying it?
There were other answers in that post about how to serialize the data, but I am afraid that will skew the results I get with the static object.
java.io.NotSerializableException - This happens if your class isn't implementing Serializable. Object of Serializable class will be written in file as sequence of bytes containing all information of that object.
If you don't want to use it then there are other ways to serialize object like JSON or MessagePack ... Just do research and find one that fits your needs best.
You can use a JSON serializer like Jackson to do this. Ideally the object would have relevant getters for the data you mention that you need to remain intact. Even if the data is private, you can tell Jackson to serialize it anyways using reflection.
ObjectMapper mapper = new ObjectMapper();
// You can use these options if the object doesn't have getters
// for fields that need to be saved, and the fields are private.
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
// Save the string representation somewhere
String yourObjectAsAJsonString = mapper.writeValueAsString(yourObject);
// Load the object back from the string representation
YourObject yourObjectDeserialized = mapper.readValue(yourObjectAsAJsonString, YourObject.class);
Your issue with the java.io.NotSerializableException is probably not under your control because you are receiving the object via SOAP, so you can't make it implement Serializable after the fact. Using a JSON serializer like Jackson can help you get around this problem.
I think your problem is not related to SOAP or data transfer but just Java serialization. Is your class serializable? Can you write a simple main method writing and reading your instance into a file or a ByteArrayOutputStream? See here.
If/when your object is serializable you need to separate the data reading from the deserialization part. Use a ByteArrayOutputStream to collect the data (or a temporary file for very large data) and do the deserialization when the data transfer is completed.
The overall process won't be faster and this will not solve any serialization/deserialization errors, it just allows to separate the two parts allowing you to use different threads or asynchio to better utilize the server resources.

Detect when object is getting serialized

I have a class / object that uses a listener interface. As far as I understand, those can't be serialized, at least I get an NotSerializableException when trying to.
Can I detect from within the object when I's gettings serialized (some form of callback) so I can remove the listener from the object?
I know I can set the listener to null from outside of the object, but it would be easier the way I described.
Don't do this. make your class implement Parcelable and provide the serialization methods yourself. Then you can decide which members get serialized and how that is done.

Persisting a Parcelable object in Android

I have a class in my Android app that I've made Parcelable so that it can be passed between Activities.
I would like to be able to save this object to the filesystem. It seems that since I've already implemented Parcelable, it would make sense to pipe the output of this to the filesystem and read it back later.
Is there a correct way to do this? Or must I implement both Parcelable and Serialiazble if I want to both pass the object between Activities and also save it to the filesystem?
From http://developer.android.com/reference/android/os/Parcel.html
Parcel is not a general-purpose serialization mechanism. This class (and the corresponding Parcelable API for placing arbitrary objects into a Parcel) is designed as a high-performance IPC transport. As such, it is not appropriate to place any Parcel data in to persistent storage: changes in the underlying implementation of any of the data in the Parcel can render older data unreadable.
For this problem, I did the following:
Implemented Serializable in my object
Added a toJSON() method to convert the object to a JSON object
Used a custom JSONSerializer to write the JSON objects to a file
Added a constructor that takes a JSON object as a parameter, used by the custom JSONSerializer
It ended up being pretty simple...I can paste some sample code if needed.

Better way to store data in java?

I am currently working on a videogame, and i want to have the user be able to save their character to a new file. I know how to use the file io (for the most part), but i have been using the 'serialize' to serialize a whole object (that contains all the variables for the character) and save it to a file. The problem is that i am constantly updating the object and making changes to it, so when i try to load the old character with the new object, it errors and crashes. Same with levels as-well (an object holding a few 2d-array of variables).
There must be a better way to do this so it is compatible with future versions. If there is a way, would anybody please offer some source code and/or a link to a nice tutorial? All help is appreciated, thanks!!!
Use XML or an embedded database (fast and lightweight) such as Derby or H2. You could even use a plain old properties file.
In fact, see if the properties file will work for you. And only if that won't work, try XML or the embedded database approach.
if you are looking for java serializers here is the benchmark for you https://github.com/eishay/jvm-serializers/wiki/
Apache Avro seems to perform well.
Another way is to store the values in the persistent store like HSQLDB or H2 db and load it to memory at startup and persist when needed.You can also use SQLite (for driver check this)
You can implement Externalizable instead of Serializable, and in the readExternal() and writeExternal() methods you can put the logic to read/write the object. This way you have full control of serialization/deserialization and can make changes fairly easily. Alternatively you can use JSON serialization by using Gson. I would not recommend XML, but if you want to you can check out xstream for the same thing.
If you are extending your objects in backwards compatible ways, i.e. add fields, and not removing fields. Make sure that you have declared a serialVersionUID as per the serializable javadoc.
http://download.oracle.com/javase/1.5.0/docs/api/java/io/Serializable.html
One additional option to consider since you're already using serialization, you could implement Externalizable instead of Serializable. The code you use to serialize objects would remain the same. However in your class you would specify exactly how you want it serialized by overriding readExternal() and writeExternal(). E.g.:
public class MyClass implements Externalizable {
private int foo;
private String bar;
public readExternal(ObjectInput in) {
foo = in.readInt();
bar = in.readUTF();
}
public writeExternal(ObjectOutput out) {
out.writeInt(foo);
out.writeUTF(bar);
}
}
Just be sure to keep the order the same when reading and writing. Try to only add fields, however if you need to remove a field leave a gap to account for old versions.
Ultimately though if you're making a lot of changes it might best to switch to a properties or XML file as LES2 suggested. It'll be more portable and readable that way.
This game uses java.util.prefs.Preferences for cross-platform convenience. Because keys are stored individually, new additions rarely interfere with existing entries.

Serialize KeyguardLock

I am writing an android application and I need to have two classes use the same KeyguardLock object but I am experiencing extreme difficulty in sharing (via serialization) that object. I have tried using the serialization stackoverflow example link but that didn't work at all. I get a "not serializable" IO exception trying to save the object. I have also tried using JSONObject.
Any ideas? Has anyone run into a similar problem?
Why are you trying to serialize it? A object can only be serialize if it implements Serializable which KeyguardLock doesn't.
If you're trying to pass it around Activities, either create a custom Application object and store it there. Or use a public static variable in a class and access it via that. The static variable is probably the better option for this.

Categories

Resources