I was going through a blog and one question came to my head. Is it possible to overwrite the way ObjectOutputStream is writing.
Let's say i am writing to a file out.dat i.e.
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("C:\\out.dat")));
out.writeObject(o);
When i opened the file out.dat in Notepad++, i saw the binary data. Which makes sense. What if, I would like to customize the way this data is being written. Lets say i want my out.dat file in JSON format (Thats just an example, It could be any other format). What method should i overwrite to do this?
You'll be able to do what you want by implementing Externalizable and overriding the writeExternal and readExternal methods. See http://download.oracle.com/javase/7/docs/platform/serialization/spec/output.html#3146 for details.
Note that it will allow customizing the output of the serialization of one object, but not the format of the whole stream. You will thus find your JSON string inside other binary data.
i think that you shouldn do it, because this format is used to keep comunication between tiers (work with distributed objects on a network). What you can do is just create a handler that store your object in a file using your pretty format.
You can make your object implement Externalizable and have full control over serialization. Use e.g. google-gson for JSON when implementing the readExternal / writeExternal methods.
In your scenario , where you are looking for a custom serialization mechanism , I would recommend that you implement Externalizable interface and provide implementations of methods
public void writeExternal(ObjectOutput out) throws IOException
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
Its entirely up to you how you want to serialize in this case.
I'm pretty sure that java does not have internal support for serializing to JSON. In my opinion your best bet is to create a interface for a getting the JSON and have any objects you want serialized to JSON implement this interface:
public interface IJSONSerializable{
public String getSerializedForm();
}
And then use a basic FileOutputStream to output since (as I understand it) the ObjectOutputStream is used to serialize a object to binary and does not have inherent support for JSON.
Other Thoughts
If you choose to go this way you could write a helper class for writing out things such as a property and a value.
Well Java itself has no built-in support for JSON serialization, but then I'm sure you can find frameworks that do that - or just write it yourself for simple classes.
So for any class you want to serialize in JSON format just overwrite
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
Shouldn't be too hard if there's some JSON framework out there that gives you the data of one instance in string format and vice versa.
Related
How can I serialize and deserialize JavaBeans without using JSON, Protobuf, Java serialization API, and other serializations? I have to implement this interface instead:
interface Encode
{
byte[] serialize(Object anyBean);
Object deserialize(byte[] byteArray);
}
How can this be done?
You can implement your own solution but the existing APIs available are providing really good solutions, why bypassing them?
I used Jersey to create a JAR-RS Web Service that responds with JSON formatted data.
When a request arrives, with the #Path annotation, a method captures the request processes it and return something.
For example, I created a JSONArray object called jsonArray in the method that handles the request. I can use return jsonArray.toString(); to get a String and send it back. I can also use return jsonArray and JAXB(the annoation #XmlRootElement in the JSONArray class and #Produces({ MediaType.APPLICATION_JSON}) in the method) to automatically serialize the object in JSON format.
I would like to know what is the difference between manually sending back a String and automatic serialization by using annotations.(Performance?)
No, there is no output difference. The main difference is that return jsonArray can be considered to be more readable (especially for other programmers), while return jsonArray.toString() is more explicit. The problem with the former is that things are more obscure as someone reading your code needs to understand that something that gets the jsonArray object silently serializes it.
Another difference between approaches is that letting the framework do it guarantees that eventual updates in the framework will be reflected in the way things get serialized. The toString() method was not originally designed to provide a serialized view of an object, which can later be used to get the object back, but to simply provide a textual (even incomplete) representation of the object.
If the class you are using does not provide serialization or if the provided serialization does not generate JSON (or whatever format you want) correctly, you can always create your own serialization. Wrap the object inside of one belonging to a class that you defined and make such a class serializable. Then provide the following methods:
private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
And, yes, they should be private. See more here: Discover the secrets of the Java Serialization API
I have a stock control system being used and i have a LinkedList to hold stock objects, now i need to add a method to the program that will allow me to save the linked list to a file and load the list from the file.
public void loadStockData(String filename)
and
public void saveStockData()
How would I achieve this?
Make sure your objects support serialization, hint: implements Serializable. http://docs.oracle.com/javase/6/docs/api/java/io/Serializable.html
Then, use java.io.ObjectOutputStream to save and java.io.ObjectInputStream to read the list.
http://www.tutorialspoint.com/java/java_serialization.htm
You did not mention if the file should be human readable.
If not then serialize the LinkedList object itself to the file given that the object it contains is also Serializable. You can use ObjectOutputStream to do that. Provide a FileOutputStream to the ObjectOutputStream
If you need in some specific format then you need to write the logic and using FileOutputStream you can write the file.
In serialization mechanism,we are wrote the object into stream using objectinputstream and object outputstream.These objects passing across the network.In this mechanismusing a Object input/output stream.So Can i use File INPUT/OUTPUT Streams instead of calling serialization marker interface?.
I guess You are mixing up serialization and general I/O.
Serialization is a way to transform objects into byte sequences (and back, which is called Deserialization). This way, You can transmit serializable objects over the network and store them into files.
File input/output streams are for storing/reading any kind of data to/from files.
when you need to transfer your object on network, you need to serialized it. Below link might be useful for you.
http://java.sun.com/developer/technicalArticles/Programming/serialization/
File I/O and Serialization are two different things. File I/O is used to read/write a file. Serialization interface is used for binary interpretation of an object. So NO, you can't use File Streams for sending over network.(maybe there is some workaround for sending data over network using file streams, but its like trying to fly with a car)
First let's concentrate on the definition:
Serialization: It is the process of converting object state into a format that can be stored and reconstructed later in the same way.
Whereas in file I/O it can't be possible to store data-structure or object and reconstructed later in the same way.
That's why we use serialization or database query methods (like sql, mongodb).
JSON/XML can also be used for serialization using its parser.
Take an example of javascript (not java, but take it like language-agnostics):
var obj = { // it's an object in javascript (same like json)
a: "something",
b: 3,
c: "another"
};
Now if you try to use file i/o in this to save in a file (say abc.txt), it will be saved as a string
which means it can't be accessed later in other code by reading this file (abc.txt) like this:
// readThisFile();
// obj.a;
But if you use serialization (in javascript using JSON natively), you can read it from the file
Since streams are additive, you can do something like
FileOutputStream fos = new FileOutputStream("/some/file/to/write/to");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(someObject);
Not sure this is what you were asking, but it's hard to tell.
Serialization/Deserialization is used to read and write objects, which not only makes compressed data, which is unreadable but also is writes it in binary. The File I/O is used for reading and writing. It appears that you do not want to serialize, if you don't, well do not use it. Read and write your files in text.
In serialization mechanism,we write the object into s stream using
ObjectInputStream and ObjectOutputStream.
Ok
These objects are passed across the network.In this mechanism using a
ObjectInput/Output stream.
I am following you.
So can I use File Input/Output streams instead of calling
serialization marker interface?.
Here you lost me. Do you mean to send an object over the network or just to serialize it?
Of course you can use whichever Input/Output streams along with ObjectInput/ObjectOutput streams to serialize objects to different media.
For instance:
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("jedis.bin"));
out.writeObject(new Jedi("Luke"));
Would serialize the object into a file called jedis.bin
And the code
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOputStream out = new ObjectOutputStream(byteStream);
out.writeObject(new Jedi("Luke"));
Would serialize the object into a memory array.
So, anything that is an output/input stream is subject of being used as the underlying stream used by ObjectInput/ObjectOutput streams.
How can I implement serialization on my own. Meaning I don't want my class to implement serializable. But I want to implement serialization myself. So that without implementing serializable I can transfer objects over network or write them to a file and later retrieve them in same state. I want to do it since I want to learn and explore things.
Serialization is the process of translating the structure of an object into another format that could be easily transfered across network or could be stored in a file. Java serializes objects into a binary format. This is not necessary if bandwidth/disk-space is not a problem. You can simply encode your objects as XML:
// Code is for illustration purpose only, I haven't compiled it!!!
public class Person {
private String name;
private int age;
// ...
public String serializeToXml() {
StringBuilder xml = new StringBuilder();
xml.append("<person>");
xml.append("<attribute name=\"age\" type=\"int\">").append(age);
xml.append("</attribute>");
xml.append("<attribute name=\"name\" type=\"string\">").append(name);
xml.append("</attribute>");
xml.append("</person>");
return xml.toString();
}
Now you can get an object's XML representation and "serialize" it to a file or a network connection. A program written in any language that can parse XML can "deserialize" this object into its own data structure.
If you need a more compact representation, you can think of binary encoding:
// A naive binary serializer.
public byte[] serializeToBytes() {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
// Object name and number of attributes.
// Write the 4 byte length of the string and the string itself to
// the ByteArrayOutputStream.
writeString("Person", bytes);
bytes.write(2); // number of attributes;
// Serialize age
writeString("age", bytes);
bytes.write(1); // type = 1 (i.e, int)
writeString(Integer.toString(age), bytes);
// serialize name
writeString("name", bytes);
bytes.write(2); // type = 2 (i.e, string)
writeString(name, bytes);
return bytes.toByteArray();
}
private static void writeString(String s, ByteArrayOutputStream bytes) {
bytes.write(s.length());
bytes.write(s.toBytes());
}
To learn about a more compact binary serialization scheme, see the Java implementation of Google Protocol Buffers.
You can use Externalizable and implement your own serialization mechanism. One of the difficult aspects of serialization is versioning so this can be a challenging exercise to implement. You can also look at protobuf and Avro as binary serialization formats.
You start with reflection. Get the object's class and declared fields of its class and all superclasses. Then obtain value of each field and write it to dump.
When deserializing, just reverse the process: get class name from your serialized form, instantiate an object and set its fields accordingly to the dump.
That's the simplistic approach if you just want to learn. There's many issues that can come up if you want to do it "for real":
Versioning. What if one end of the application is running new version, but the other end has an older class definition with some fields missing or renamed?
Overwriting default behavior. What if some object is more complex and cannot be recreated on a simple field-by-field basis?
Recreating dependencies between objects, including cyclic ones.
... and probably many more.
Get the Java Source code and understand how Serialization is implemented. I did this some month ago, and now have a Serialization that uses only 16% of the space and 20% of the time of "normal" serialization, at the cost of assuming that the classes that wrote the serialized data have not changed. I use this for client-server serialization where I can use this assumption.
As a supplement to #Konrad Garus' answer. There is one issue that is a show-stopper for a full reimplementation of Java serialization.
When you deserialize an object, you need to use one of the object's class's constructors to recreate an instance. But which constructor should you use? If there is a no-args constructor, you could conceivably use that. However, the no-args constructor (or indeed any constructor) might do something with the object in addition to creating it. For example, it might send a notification to something else that a new instance has been created ... passing the instance that isn't yet completely deserialized.
In fact, it is really difficult replicate what standard Java deserialization code does. What it does is this:
It determines the class to be created.
Create an instance of the class without calling any of its constructors.
It uses reflection to fill in the instance's fields, including private fields, with objects and values reconstructed from the serialization.
The problem is that step 2. involves some "black magic" that a normal Java class is not permitted to do.
(If you want to understand the gory details, read the serialization spec and take a look at the implementation in the OpenJDK codebase.)