Deserializing multiple objects from file without using while(true) - java

I have a block of code, that deserializes multiple objects from file. How can i avoid using a while(true)?
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
filename));
while (true) {
try {
MyObject o = (MyObject) in.readObject();
// Do something with the object
} catch (EOFException e) {
break;
}
}
in.close();

You should write either a collection (with a size), or a put a marker before each object:
try {
for (;in.readBoolean();) {
MyObject o = (MyObject) in.readObject();
}
} catch (EOFException e) {
// ...
}
When you write your object, write a boolean just before (it will however take 1 byte if I do remember well that part):
for (MyObject o : iterable) {
out.writeBoolean(true);
out.writeObject(o);
}
out.writeBoolean(false);
If iterable is a collection or map, you can use default serialization:
out.writeObject(iterable); // default collection serialization
Beside, don't catch an exception for each item, catch it globally (especially EOFException!): it is better for performance reasons.
I don't know if you work with Java 7, but your code + my for loop can be written like this:
try (ObjectInputStream in = new ObjectInputStream(new FileInputStream( filename))) {
for (;in.readBoolean();) {
MyObject o = (MyObject) in.readObject();
}
} catch (EOFException e) {
// ...
}
// no need to close, the try-with-resources do the job for you.

How can i avoid using a while(true)?
You can't.
More to the point, why do you think you want to?
This is a classic example of the tail wagging the dog. EOFException is thrown to indicate end of stream. Ergo you have to catch it, and ergo you have to loop until it is thrown, ergo you have to use while (true) or one of its cognates.
The exception thought police would have you prepend an object count, taking the curious position that external data structures should be designed to suit the coder's phobias, and overlooking that you may not know it in advance, or may need to change your mind, or may need to exit prematurely; or would have you write a null as an end-of-stream marker, overlooking that it prevents the use of null for any other purpose; and in both cases overlooking the fact that the API is already designed to throw EOFException, and already works the way it already works, so you already have to code accordingly.

The code that I'm proposing let you to serialize and deserialize multiple objects really easily without having any problems and avoiding the awful (in my opinion) while true:
public class EntityClass implements Serializable{
private int intVal;
private String stringVal;
public EntityClass(int intVal, String stringVal) {
this.intVal = intVal;
this.stringVal = stringVal;
}
#Override
public String toString() {
return "EntityClass{" +
"intVal=" + intVal +
", stringVal='" + stringVal + '\'' +
'}';
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
EntityClass a = new EntityClass(1, "1");
EntityClass b = new EntityClass(2, "2");
EntityClass c = new EntityClass(3, "3");
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream("out"));
stream.writeObject(a);
stream.writeObject(b);
stream.writeObject(c);
stream.close();
ObjectInputStream streamRead = new ObjectInputStream(new FileInputStream("out"));
EntityClass[] entities = new EntityClass[3];
int cont = 0;
try {
while (streamRead.available() >= 0) {
entities[cont] = (EntityClass) streamRead.readObject();
System.out.println(entities[cont]);
cont++;
}
} catch (EOFException exp) {
} finally {
streamRead.close();
}
}
}

Related

How to properly close input streams?

There are two methods of doing the same thing. The first:
public String getIpByName(String name) {
var builders = NetworkUtil.buildProcess(name);
try (var ip = new BufferedReader(new InputStreamReader(executor.execPipelineAndGetInputStream(builders)))) {
return ip.lines().collect(Collectors.joining());
} catch (IOException exception) {
throw new NotFoundException(name);
}
}
Second:
public String getIpByName(String name) {
var builders = NetworkUtil.buildProcess(name);
try (var result = executor.execPipelineAndGetInputStream(builders)) {
var input = new InputStreamReader(result);
var reader = new BufferedReader(input);
var ip = reader.lines().collect(Collectors.joining());
input.close();
reader.close();
return ip;
} catch (IOException exception) {
throw new NotFoundException(name);
}
Which method would be more correct?
The second one is never correct. Either the close() calls are important, or they are not. If they are important, they should be try/finally-ied or try-with-resourced. If they are not important, they are not important, and you should not bother writing the statements.
Thus, we have 3 alternatives, not 2, and only your first alternative is left unchanged:
Second:
public String getIpByName(String name) {
var builders = NetworkUtil.buildProcess(name);
try (var result = executor.execPipelineAndGetInputStream(builders)) {
var input = new InputStreamReader(result);
var reader = new BufferedReader(input);
return reader.lines().collect(Collectors.joining());
} catch (IOException exception) {
throw new NotFoundException(name);
}
}
and there's a third, using the resource chaining feature of try-with-resources:
public String getIpByName(String name) {
var builders = NetworkUtil.buildProcess(name);
try (var result = executor.execPipelineAndGetInputStream(builders);
var input = new InputStreamReader(result);
var reader = new BufferedReader(input)) {
return reader.lines().collect(Collectors.joining());
} catch (IOException exception) {
throw new NotFoundException(name);
}
}
Of these 3 options, you get into a bit of a debate; the first option seems fine; the implementations of these so-called 'filter streams' (those are readers/writers/outputstreams/inputstreams that 'wrap' another stream) have the deal that close()ing them will close the thing they wrapped. Thus, ordinarily #1 seems fine, but if an exception were to occur in the constructor of the filterstream, then you leak a resource. Will these exceptions occur? Ordinarily impossible, but not always, here's a trivial way to cause a commonly used filterstream to crash in construction:
new InputStreamReader(someData, "some non existing charset");
Thus, I strongly advise against the first. That leaves door #2 and door #3: It really doesn't matter; I think the second one is probably the most readable, but the problem with the second option is that various IDE and linting tools will complain about it, they have a hard time telling the difference between resource-representing streamlikes, and filters/memory-only streamlikes. This is not their fault, really: How could they possibly know if the InputStream returned by your execPipelineAndGetInputStream method is supposed to be 'thing you need to close' or 'thing you can close but it doesnt matter' or 'thing you should not be closing at all'?
The first one is more correct, since the second one does not close the InputStreamReader and BufferedReader when there is an exception thrown, while the first example is using the try-with-resources statement (https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html).
For the first example to be correct you should move the lines closing resources to the finally clause:
try (var result = executor.execPipelineAndGetInputStream(builders)) {
var input = new InputStreamReader(result);
var reader = new BufferedReader(input);
var ip = reader.lines().collect(Collectors.joining());
return ip;
} catch (IOException exception) {
throw new NotFoundException(name);
} finally {
input.close();
reader.close();
}

Code after readObject() does not run

I am working on a UI which reads serialized object from zookeeper, deserializes it and then converts it into JSON. For some reason I am not able to deseerialize the MQTopic object. But I am able to do the same with other objects.
This is the part which converts the byte[] into the MQTopic object.
if (tester != null && tester.contains("com.ibm.mq.jms.MQTopic")) {
System.out.println(getValue());
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
}
Here value is a byte array of the object after serialization.
Nothing runs after topic = (MQTopic) is.readObject(); . Not even the print statements. The program neither terminates nor an exception is thrown or caught.
EDIT : Whole Method
public String getStrValue() {
FtpConnectionInfo ftp = null;
MQTopic topic = null;
try {
String tester = new String(this.value, "UTF-8");
if (tester != null && tester.contains("FtpConnectionInfo")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
ftp = (FtpConnectionInfo) is.readObject();
in.close();
is.close();
Gson gson = new Gson();
return gson.toJson(ftp);
} else if (tester != null
&& tester.contains("com.ibm.mq.jms.MQTopic")) {
ByteArrayInputStream in = new ByteArrayInputStream(this.value);
ObjectInputStream is = new ObjectInputStream(in);
System.out.println("after deserializing..");
topic = (MQTopic) is.readObject();
System.out.println("after typecasting..");
System.out.println(topic.getTopicName());
System.out.println(topic.toString());
is.close();
in.close();
} else {
return new String(this.value, "UTF-8");
}
} catch (UnsupportedEncodingException ex) {
System.out.println("unsupported error ");
ex.printStackTrace();
//logger.error(Arrays.toString(ex.getStackTrace()));
} catch (Exception e) {
System.out.println("Exception in new logic.");
e.printStackTrace();
}
System.out.println("im out of try");
return null;
}
The FTP if loop works fine, but the Topic loop does not work beyond typecasting.
EDIT 2: This how the other team stores the object into Zookeeper
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(out);
os.writeObject(obj);
return out.toByteArray();
}
The byte[] is stored in Zookeeper and that is what I am retrieving in my UI.
EDIT 3: I did a debug of the process and at the point where is is called, these are the values. Can anyone tell me if the object is right ?
You're doing this wrong. You should deserialize the object first, and then use instanceof to see what type it is. Converting binary data to String is poor practice at the best of times.
Your actual symptom is not credible. An exception must be thrown, or else you are blocking earlier than stated.
ObjectInputStream's readObject is a blocking method. First check using the available method if there is something to read without blocking.
available would most probably return 0 in this case.
This might be only half the solution you are looking for, but I think this would let you know if you have anything to read or not.

Unable to read serializable class from .dat file

I try to write a keyholder, and I want to write the passwords to a .dat file using ObjectOutputStream, and then read them using ObjectInputStream. This is my code for writing the objects:
public void toFile()
{
try
{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("passwords.dat"));
for(int i = 0; i<this.nrOfPW; i++)
{
if(this.PWlist[i] instanceof longPW)
{
oos.writeObject((longPW)this.PWlist[i]);
}
else
{
oos.writeObject((PinPW)this.PWlist[i]);
}
}
oos.close();
}
catch(IOException e)
{
e.getStackTrace();
}
}
This seems to work, but when I try to read the file again and put the objects in my PWlist array it says that PinPW isn't serializable, even though PinPW implements Serializable and it's imported. The base class of PinPW (Info) also implements Serializable and imports it. This is the code where I read the file:
public void fromFile()
{
try
{
ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("passwords.dat"));
while(objIn.readObject() != null)
{
if(this.nrOfPW == this.PWlist.length)
{
expand(10);
}
if(objIn.readObject() instanceof PinPW)
{
this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject();
this.nrOfPW++;
}
else
{
this.PWlist[this.nrOfPW] = (longPW)objIn.readObject();
this.nrOfPW++;
}
}
objIn.close();
}
catch(EOFException e)
{
e.getStackTrace();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
}
The PWlist array is a Info array, and PinPW and longPW extends Info.
What do I do to fix this problem?
Let's fix the "first bug, first" ...
In this code:
while(objIn.readObject() != null) // reads object, tests then *discards* it
{
...
if(objIn.readObject() instanceof PinPW) // reads object, tests then *discards* it
{
this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject(); // conditionally read an object
this.nrOfPW++;
}
else
{
this.PWlist[this.nrOfPW] = (longPW)objIn.readObject(); // conditionally read an object
this.nrOfPW++;
}
}
Each time around your loop iteration, you actually read 3 objects. The first time you read an object to check there was one in the stream, the next time you read one and determine it's type, then discard it. Then you read a third object and cast it based on what the type of the discarded object was.
In addition, as EJP correctly points out, the correct way to determine End of Stream for an ObjectInputStream is to catch the end of file exception.
You want to do this instead:
try
{
while (true)
{
final Object o = objIn.readObject(); // read the object from the stream
...
if (o instanceof PinPW)
{
this.PWlist[this.nrOfPW] = (PinPW) o; // cast to correct type
this.nrOfPW++;
}
else
{
this.PWlist[this.nrOfPW] = (longPW) o; // cast to correct type
this.nrOfPW++;
}
}
}
catch (EOFException e)
{
// end of stream reached ...
// ... close the file descriptor etc ...
}
You have a problem here.
while(objIn.readObject() != null)
{
if(this.nrOfPW == this.PWlist.length)
{
expand(10);
}
if(objIn.readObject() instanceof PinPW)
{
this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject();
this.nrOfPW++;
}
else
{
this.PWlist[this.nrOfPW] = (longPW)objIn.readObject();
this.nrOfPW++;
}
}
You are reading an object many times. Try to save it and then work with it.
if(objIn.readObject() instanceof PinPW) reads one, reads twice, this.PWlist[this.nrOfPW] = (PinPW)objIn.readObject(); reads three times, when it should be only once.
PS: use Greg Kopff syntax inside a while and without the final keyword because you want to save more objects in it.
I just wanted to point out the if-else block in the toFile() function is completely pointless. writeObject() takes an Object argument. It doesn't care what type of Object it is, as long as it's serializable.
While your fromFile() method is seriously flawed, it would not cause a NotSerializableException. I believe the exception you're referring to actually happened in toFile().
The cause is very simple: you didn't fully read and understand the documentation of ObjectOutputStream. To be specific, the Object and all its non-transient fields and all non-transient fields in its ancestor classes has to implement the Serializable. It must also have a public no-arg constructor.

handling EOFException in java

I have created a method in my java assignment to write into a file from a LinkedList (I used serialization) , then I have created another method to read the file into the inkedList. The following is my method's body:
try {
FileInputStream fin = new FileInputStream("c:\\Info.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
Employee e = (Employee) ois.readObject();
linkP.add(e);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
but it doesnt work right. I think this part:
Employee e = (Employee) ois.readObject();
linkP.add(e);
reads only the first object of the file into the linkedlist and ignores other objects. I surrounded it for loop and while loop several times but it causes EOFException. How can I change my method to read all of the file's objects into the LinkedList?
If you used LinkedList for serialization you should expect a LinkedList to deserialize:
linkP= (LinkedList) ois.readObject();
instead of
Employee e = (Employee) ois.readObject();
linkP.add(e);
The easiest way is to include the size of the list as the first thing written to the file. When you read the file, the first thing you retrieve is the size. Then you can read the expected number of objects.
Are you sure that the serialized file contains all of the elements? It looks to me like you might only be serializing one.
Note: Please also add the code where you create the info.ser file, since you may have corrupted the ObjectOutputStream by closing/reopening it for each object.
But to answer your question, the proper way of doing it (without catching exceptions) would be:
#Test
public void testSerializingListByEntries() throws Exception {
List<Serializable> list = new ArrayList<Serializable>();
list.add(new Date());
list.add(new Date());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeInt(list.size()); // Magic
for(Serializable o : list) {
oos.writeObject(o);
}
oos.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
int count = ois.readInt();
List<Object> newList = new ArrayList<Object>();
for(int i = 0; i < count;i++) {
newList.add(ois.readObject());
}
ois.close();
assertEquals(list,newList);
}
Yes, you need to close the streams yourself of course. Omitted for readability.
Would probably need to see how you're writing in the first place but generally:
ObjectInputStream is = null;
try
{
is = new ObjectInputStream(new FileInputStream("c:/Info.ser"));
Object object = null;
while ((object = is.readObject()) != null)
{
linkP.add(object);
}
}
catch(Exception e)
{
//Whatever you need to do
}
finally
{
//Never forget to close your streams or you'll run into memory leaks
try
{
if (is != null)
{
is.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
Also, its probably better practice for you to handle the exceptions individually but I can't really tell what the streams throw so replace the (Exception e) with everything else.
surround Employee e = (Employee) ois.readObject();
linkP.add(e);
with a for loop as you suggested and surround the .readObject call with a try/catc(EOFException)
Just catch EOFException separately inside your reading loop and process it accordingly, i.e. break out of the loop.

Java: Try-Catch-Continue?

Let's say I can a set of statements:
try {
String a = getProperty("a");
String b = getProperty("b");
String c = getProperty("c");
} catch(Exception e) {
}
Now, lets say property b was not found and the function throws an exception. In this case, how would I just continue or perhaps set b to null without having to write a try-catch block for each property? I mean, a,b,c exist but sometime they might not be found at all during which an exception is thrown.
Assuming you can't change the function so that it returns null when the property isn't found, you are kind of stuck wrapping everything in its own try catch block -- especially if you want for every value that can be retrieved to be retrieved (as opposed to letting the first value that fails cancel the whole operation.)
If you have a lot of these properties to retrieve, perhaps it would be cleaner to write a helper method to use:
String getPropertySafely(String key) {
try {
return getProperty(key);
} catch (Exception e) {
return null;
}
}
You have to put a try-catch around each statement. There is no continue (like there is in ON ERROR ... RESUME blocks in VB). Instead of:
String a = null;
try {
a = getProperty("a");
} catch(Exception e) {
...
}
String b = null;
try {
b = getProperty("b");
} catch(Exception e) {
...
}
String c = null;
try {
c = getProperty("c");
} catch(Exception e) {
...
}
you could write:
public String getPropertyNoException(String name) {
try {
return getProperty(name);
} catch (Exception e) {
return null;
}
}
Personally I think a getProperty() is a poor candidate for throwing exceptions just for all this extra boilerplate required
Since you are using the same function each time you might be able to put this in a loop:
String[] abc = new String[3];
String[] param = {"a", "b", "c"};
for (int i = 0; i < 3; i++) {
try {
abc[i] = getProperty(param[i]);
} catch(Exception e) {
}
}
but this is rather contrived and would only be useful for a large number of properties. I suspect you will have to simple write 3 try-catch.
You should reconsider how getProperty is handled if you plan to use many of them because there isn't a plain way to do it.
You can exploit finally statement but you still need a try-catch for every call.

Categories

Resources