Java serialisation and dealing with objects [duplicate] - java

This question already has an answer here:
Java hashset how to serialise multiple objects
(1 answer)
Closed 6 years ago.
I'm using the code below, to get data from a file saved on my desktop to input into the game that I'm making.
try {
FileInputStream saves = new FileInputStream("/Users/Prodigy958/Desktop/Hack_exeSaves.ser");
ObjectInputStream in = new ObjectInputStream(saves);
test = (player) in.readObject();
in.close();
saves.close();
} catch(IOException error) {
error.printStackTrace();
return;
} catch(ClassNotFoundException error) {
error.printStackTrace();
return;
}
There is also the section which takes the player object and inputs it into a file.
player realPlayer = new player();
realPlayer.name = newName;
realPlayer.gender = newGender;
realPlayer.hasStarted = false;
try {
FileOutputStream fileOut = new FileOutputStream("/Users/Prodigy958/Desktop/Hack_exeSaves.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(realPlayer);
out.close();
fileOut.close();
} catch(IOException i) {
i.printStackTrace();
}
The issue that I am having is that if you save more than one player data onto the file, it calls up errors because it takes all the data and turns it into one player object. Do you know an easy way I would be able to split up the data? I have thought about using multiple files to store each different object's data. I have also though about taking out the data and splitting it up into separate objects, and then working from there, however I don't know where to start on the second one.

As others have already suggested, use a Serializable implementation of java.util.Collection. (Most of the java.util collections--such as java.util.ArrayList and java.util.HashSet--are Serializable.) A collection of 0 or 1 elements shouldn't bother you (it's not relevant to the serialization of the collection) unless your game has other business requirements that care, but... in that case, that's far beyond the scope of this question, and for you to handle on your own.

Related

Serializing arbitrary Java objects

I am currently in need to serialize arbitrary Java objects since I would like to use the Hash as a key for a hash table. After I read various warnings that the default hashCode creates collisions way to often, I wanted to switch to hashing via MessageDigest to use alternative algorithms (e.g. SHA1, ...) that are said to allow more entries without collisions. [As a sidenote: I am aware that even here collisions can occur early on, yet I want to increase the likelihood to remain collision free.]
To achieve this I tried a method proposed in this StackOverflow post. It uses the following code to obtain a byte[] necessary for MessageDigest:
public static byte[] convertToHashableByteArray(Object obj) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] byteOutput = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(obj);
byteOutput = bos.toByteArray();
} catch (IOException io) {
io.printStackTrace();
} finally {
try {
if(out != null) { out.close(); }
} catch(IOException io) {
io.printStackTrace();
}
try {
bos.close();
} catch(IOException io) {
io.printStackTrace();
}
}
return byteOutput;
}
This, however, causes the problem that only objects implementing the serializable interface will be serialized/converted into a byte[]. To circumvent this issue I applied toString() to the given obj in the catch clause to enforce getting a byte[] in all cases:
public static byte[] convertToHashableByteArray(Object obj) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] byteOutput = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(obj);
byteOutput = bos.toByteArray();
} catch (IOException io) {
String stringed = obj.toString();
byteOutput = stringed.getBytes();
} finally {
try {
if(out != null) { out.close(); }
} catch(IOException io) {
io.printStackTrace();
}
try {
bos.close();
} catch(IOException io) {
io.printStackTrace();
}
}
return byteOutput;
}
However, this still feels utterly wrong for me. So my question is, whether there is a better alternative to convert arbitrary objects to byte[] to be able to compute hashes. Preferably a solution that works without using additional libraries or one using well established ones like Apache Commons.
(Beside that I am also open for other approaches to obtain SHA1/SHA512 hashes of arbitrary Java objects.)
Perhaps you can use UUIDs for your objects as immutable unique identifiers?
There are so many things wrong here...
You should have proper key classes with equals and hashCode implemented, instead of using random objects.
Serialization performance overhead can easily mean that such map will be slower than even trivial iteration search.
Default hashcode should not be used in most cases, as it might be different for objects which are 'equal' from business point of view. You should reimplement hashcode together with equals (which comes back to point 1). Whenever it has collisions due to pointer aliasing is irrelevant if it won't work poperly
Way overcomplicated method of closing in-memory streams. Just close them one after another, it is not external resource - if it fails, just let it fail, you don't need to close everything 100% in case of failures. You can also use one of closeable utilities (or try/catch with resources) to avoid some overhead
You don't need complicated digest of that byte array - use Arrays.hashCode, it WILL be good enough for your use cases (remember - don't do it anyway, point 1)
If you are still reading and still not willing to implement point 1, go back to point 1. And again. And again.
And to finally answer you question, use hessian serialization.
http://hessian.caucho.com/doc/hessian-overview.xtp
It is very similar to java one, just faster, shorter output and allows serializing objects which do not implement Serializable interface (at the risk of messing things up, you need to set special flag to allow that).
If you want to serialize a given object, i suggest you change your méthod like this :
public static byte[] convertToHashableByteArray(Serializable obj){
..........
..........
}

How do I save the state of my program? [duplicate]

This question already has answers here:
How can I save the state of my program and then load it?
(2 answers)
Closed 6 years ago.
For my program I have two buttons, "Add" and "Save". When I click "Add" a button is added to the JPanel. My question is, how do I save the current state of my program with all the buttons the user added? Do I use serialization?
Here is a snippet of my code:
public class saveButton
{
//JFrame and JPanels have been declared earlier
class ClickListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String str = JOptionPane.showInputDialog("Name of button");
JButton b = new JButton(str);
frame.add(b);
}
}
ActionListener addButtonClicked = new ClickListener();
b.addActionListener(addButtonClicked);
class ClickListenerTwo implements ActionListener
{
public void actionPerformed(ActionEvent f)
{
//save all of the program
}
}
}
You can only serialize (meaning straight Java serialization) if your object and every non-transient member within the class supports serialization. This is not always possible.
However, you could define your own configuration object that contains the necessary state information and save it whenever (could be just before closing app, could be every time the state changes, it's up to you) and serialization might be a way to do it
It depends on how you save it. You can write the state onto a file and then recover it from there by reading it. The number of buttons and the order etc. You have to decide on the format on how you want to save it too. For example you may want to store in one line
Save,JButton,imageSrc,xpos,ypos
So when you read that line and split on ',' you know that Save is the text, JButton is the class, etc.
Hope this helps
I would write my own file format rather than deal with the overhead of Java's serialization. This has the benefit of being more easily readable in other languages and of slightly better performance. Furthermore, as #MadProgrammer pointed out the Serialization of Swing object is not currently supported and will not be compatible with future releases:
Warning: Serialized objects of this class will not be compatible with
future Swing releases. The current serialization support is
appropriate for short term storage or RMI between applications running
the same version of Swing. As of 1.4, support for long term storage of
all JavaBeans™ has been added to the java.beans package. Please see
XMLEncoder.
(link)
Here is an example:
public void saveState(){
File stateFile = new File("./stateFile");
FileOutputStream fos = new FileOutputStream(stateFile);
DataOutputStream dos = new DataOutputStream(fis);
for(JButton button : jButtons){ //store the buttons in an arraylist when they are created (you could also iterate over the added components and use instanceof)
dos.writeUTF(button.getText());
}
dos.writeUTF("end"); //have some sort of end marker
dos.flush();
dos.close();
fos.flush();
fos.close()
}
public void loadState(){
File stateFile = new File("./stateFile");
FileInputStream fis = new FileInputStream(stateFile);
DataInputStream dis = new DataInputStream(fis);
String name;
while(!(name = dis.readUTF()).equals("end")){
add(new JButton(name));
}
fis.close();
}

Serializable Errors with Java Object

Edit, Here's how i solved using the comments
So after trying different ways of serializing and looking through my code, I finally found out that each object drawn in the renderer contains FloatBuffers. I created a capsule class thanks to Ted Hopp. Then I tried returning the float representation of the FloatBuffers using .array(), which you can't do. My guess is because these are running on threads. So using a suggestion from Learn OpenGL ES to use get, i instead did
public float[] getVertexBuffer()
{
float[] local = new float[vertexBuffer.capacity()];
vertexBuffer.get(local);
return local;
}
Which does work and returns the float[].
Then i store them all in a capsule object for each mGrid object i created
Encapsulate capsule = new Encapsulate(values);
for(int i = 0; i < values[0]; i++)
{
for(int j = 0; j < values[1]; j++)
{
capsule.storeVertex(i,j,mRenderer.mGrid[i*values[1] + j].getVertexBuffer());
capsule.storeColors(i,j,mRenderer.mGrid[i*values[1] + j].getmColors());
capsule.storePillar(i,j,mRenderer.mGrid[i*values[1] + j].getPillarPositions());
}
}
Which I can then ultimately save because it's serializable. Thank you all
PROBLEM DESCRIPTION
So i'm trying to save a GLSurfaceView object, whose class is denoted as
class GLWorld extends GLSurfaceView implements Serializable
Now I'm sure as i do the saving correctly.
public void saveSimulation()
{
String fileName = "Test Save";
try {
FileOutputStream fos = openFileOutput(fileName, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(mGLView);
Log.d("Save","Successfully Written");
oos.close();
fos.close();
} catch (FileNotFoundException e) {
Log.d("Save","File not found exception");
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
Log.d("Save","IO exception");
// TODO Auto-generated catch block
e.printStackTrace();
}
finish();
}
But i'm getting an error i have no clue how to fix. I've spent hours looking around but haven't found anything like it.
09-16 17:36:50.639: W/System.err(2996): java.io.NotSerializableException: java.nio.FloatToByteBufferAdapter
Along with many more system err lines below that, which i believe stem from this one error.
My GLWorld creates a renderer object in it which has different objects with floatbuffers in it which store vertex and color data. I can't figure out what to do to get past this error, or why those float buffers are throwing an error. Everything runs smoothly except actually trying to save this GLWorld object and it's driving me insane.
Just declaring that a class implements Serializable is not enough to successfully serialize objects of that class. The default implementation requires that every field of the class be serializable. In your case, there's a field of type FloatToByteBufferAdapter that isn't serializable (there may be more).
You can define your own serialization mechanism to serialize only what you need. The details can be found in the Serializable docs. Be aware that by subclassing GLSurfaceView, it is unlikely you will be able to successfully deserialize this class, even if you write the correct support methods. For one thing, GLSurfaceView does not have a default (no-arg) constructor, which is a requirement of Java's serialization mechanism. Also, many objects simply cannot be serialized (e.g., streams).
I suggest that you encapsulate the data you want to serialize in a helper class and limit the serialization/deserialization to those data.
Gotta assume that something within the mGLView inheritance contains FloatTOByteBufferAdapter, which isn't serializable.

Java reading serialized in objects from file into an arrayList

I'm attempting to read a file that contains serialized objects of type Contact into an ArrayList contactsCollection. The issue I'm having is that the objects Contact never get added into the ArrayList.
try
{
ObjectInputStream in = new ObjectInputStream(new FileInputStream("contactList.dat"));
Contact temp;
while (in.available()!=0)
{
temp = (Contact)in.readObject();
contactsCollection.add(temp);
}
in.close();
}
This is a known behaviour of ObjectInputStream.available, it always returns 0, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4954570. Instead, you can read objects from file until EOFException is thrown, catch it and break.
Actually, you entire approach is wrong: You should serialize the List, not each object.
All List implementations are Serializable. Just create the list, add your onjbects and serialize the list - the objects in it will be serialized too (if they implement Serializable, which obviuosly your do).
Then to deserialize, simply read in the object, and voila - you have a list with all our objects added in already.
ArrayLists are Serializable provided their contents are. If the code that stores the Contacts to the stream has them in an ArrayList, just read the list in all at once.
If not, you probably want to have the code storing the Contacts store the length first:
try (FileInputStream fis = new FileInputStream("contactList.dat"),
ObjectInputStream in = new ObjectInputStream(fis)) {
int size = in.readInt();
for (final int i = 0; i < size; ++i) {
contacts.add((Contact) in.readObject());
}
} catch (IOException e) {
// Handle exception
}
Mixing available and readObject is unwise; available would tell how many bytes are available without causing the stream to block, except that Evegniy's comment applies. Those bytes may not represent a complete object.
If you can't get the code writing to the stream to put the size in first, you'll simply have to loop through and depend on the fact that an EOFException is an IOException.

java string scramble

I am currently working on a program that takes user data (name, address, phone). I want to make the data unreadable when I save it. Since it won't be a released program, I don't want to use a cipher that is too complicated, just a simple and quick scramble/unscramble algorithm.
How about defining a class (let's say Foo) and create instances of that class those which can hold the data, then put the objects into a list. After that, save the list object as a binary file. Something like this:
public static void saveObject(List<Foo> obj, String filePath)
{
OutputStream os = null;
try
{
os = new ObjectOutputStream(new FileOutputStream(filePath));
os.writeObject(obj);
}
catch(Exception ex){}
finally
{
os.close();
}
}
Then you can load it like:
public static List<Foo> loadObject(String filePath)
{
List<Foo> obj = null;
InputStream is = null;
try
{
is = new ObjectInputStream(new FileInputStream(filePath));
obj = (List<Foo>) is.readObject();
}
catch(Exception ex){}
finally
{
is.close();
}
return obj;
}
Note that you need to implement the Serializable interface to use this object serialization.
you just need to understand that its a matter of strength of your algorithm, because according to your post, you do need some way of encryption/decryption.
You can think about a lot of ways to "hide" your data but this "defense" can be broken in a relatively easy way... So its up to you to decide.
The easiest implementations are (naive):
- substitute each letter in your string with some number.
- play with ascii values of your letters in string.
Again the real question here is whether it is good enough???
From the point of view of "security" - definitely not.

Categories

Resources