How to workaround readObject similar to readLine - java

I am reading a file which contain many serialized objects.
I want to deserialize them back and realized that we cannot use readObject like readLine ie
while (ois.readObject != null) {
}
would throw an exception. We also dont have hasNext and next sort of mechanism in place from my knowledge.
How is the problem of reading object fixed in real world ?

Catch EOFException, and close and break when you get it.
readObject() only returns null if you wrote a null, and that doesn't have to imply the end of the stream.

Assuming you're trying to load Person objects, you could try something like:
ArrayList<Person> persons = new ArrayList();
while (true) {
try {
persons.add((Person) ois.readObject());
} catch (EOFException e) {
break;
}
}
Or instead of serializing the individual object, you could add your objects to an array or arraylist and serialize the list object. Then you can easily deserialize the list object and you won't have to deal with EOFException. See the example in John Purcell's serialization tutorial.

Related

How to read DataInputStream until the end without needing to catch an EOFException?

Suppose we have some binary data byte[] data that only contains Integers. If I wanted to read this data utilizing a DataInputStream, the only approach I can come up with is the following:
DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
try {
while (true){
int i = in.readInt();
}
} catch (EOFException e) {
// we're done!
} catch (IOException e){
throw new RuntimeException(e);
}
What bugs me about this is that reaching the end of the stream is expected and it would exceptional only if no exception was thrown, what IMO defeats the purpose of exceptions in the first place.
When using Java NIO's IntBuffer, there's no such problem.
IntBuffer in = ByteBuffer.wrap(data).asIntBuffer();
while (in.hasRemaining()){
int i = in.get();
}
Coming from C# and being in the process of learning Java I refuse to believe that this is the intended way of doing this.
Moreover, I just came across Java NIO which seems to be "quite new". Using IntBuffer here instead would be my way of procrastinating the matter. Regardless, I wanna know how this is properly done in Java.
You can't. readInt() can return any integer value, so an out-of-band mechanism is required to signal end of stream, so an exception is thrown. That's how the API was designed. Nothing you can do about it.
Since you are coming from .NET, Java's DataInputStream is roughly equivalent to BinaryReader of .NET.
Just like its .NET equivalent, DataInputStream class and its main interface, DataInput, have no provision for determining if a primitive of any given type is available for retrieval at the current position of the stream.
You can gain valuable insight of how the designers of the API expect you to use it by looking at designer's own usage of the API.
For example, look at ObjectInputStream.java source, which is used for object deserialization. The code that reads arrays of various types calls type-specific readXYZ methods of DataInput in a loop. In order to figure out where the primitives end, the code retrieves the number of items (line 1642):
private Object readArray(boolean unshared) throws IOException {
if (bin.readByte() != TC_ARRAY) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
int len = bin.readInt();
...
if (ccl == Integer.TYPE) {
bin.readInts((int[]) array, 0, len);
...
}
...
}
Above, bin is a BlockDataInputStream, which is another implementation of DataInput interface. Note how len, the number of items in the array stored by array serialization counterpart, is passed to readInts, which calls readInt in a loop len times (line 2918).

Flattening a JSONObject in Java - Recursion causing StackOverflowError

I've been writing a method to "flatten" a codehaus JSONObject in Java. Unfortunately, I'm seeing a StackOverflowError in the recursion through the object nests, but I'm finding it difficult to debug. Here is the error I'm seeing:
Exception in thread "main" java.lang.StackOverflowError
at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
at java.util.LinkedHashMap$LinkedHashIterator.<init>(LinkedHashMap.java:345)
at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
at java.util.LinkedHashMap$KeyIterator.<init>(LinkedHashMap.java:383)
at java.util.LinkedHashMap.newKeyIterator(LinkedHashMap.java:396)
at java.util.HashMap$KeySet.iterator(HashMap.java:874)
at org.codehaus.jettison.json.JSONObject.keys(JSONObject.java:533)
at org.codehaus.jettison.json.JSONObject.toString(JSONObject.java:1079)
at org.codehaus.jettison.json.JSONObject.valueToString(JSONObject.java:1210)
I'm using Iterator to loop the keys, and using hasNext() and next() to ensure that I should only be able to access specific object keys.
I started testing with a simple JSONObject of:
JSONObject json = new JSONObject("outer":{"field1":"value","inner":{"field2":12345,"field3":"example#example.com"}});
/*
"outer":{
"field1":"value",
"inner":{
"field2":12345,
"field3":"example#example.com"
}
}
*/
This should result in a single nest containing fields1|2|3.
Here is the code I have so far:
private static JSONObject flatten(JSONObject object, JSONObject flattened){
if(flattened == null){
flattened = new JSONObject();
}
Iterator<?> keys = object.keys();
while(keys.hasNext()){
String key = (String)keys.next();
try {
if(object.get(key) instanceof JSONObject){
flattened.put(key, flatten(object.getJSONObject(key), flattened));
} else {
flattened.put(key, object.get(key));
}
} catch(JSONException e){
System.out.println(e);
}
}
return flattened;
}
I have been debugging this for a while now, but haven't been able to make any headway - so I'd appreciate any pointers with this. Thanks in advance for any help - if any more info is needed, just leave a comment.
Replace
flattened.put(key, flatten(object.getJSONObject(key), flattened));
by
flatten(object.getJSONObject(key), flattened);
Here it gives me {"field1":"value","field2":12345,"field3":"example#example.com"} and I think that's what you want
Notice that when you call the function recursively, you pass the "flattened" object into the function, and then it returns it back to you, which you then add to "flattened". Thus you are adding the object to itself, creating a circular reference
When you do the recursive call, don't add the result back into the object. Just do:
flatten(object.getJSONObject(key), flattened);

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.

Recursively reading any java Object and pulling out complex types into a hash map

I need to write a utility program which would accept a blank HashMap and any object as arguments and return the HashMap
public HashMap returnMap(HashMap map,Object parseThisObject){
//logic to strip all children, children of children...... and place it in HashMap
//return map
}
This object contains a lot of objects within it and those objects within has a lot of children and the lineage goes on.
My utility must be generic enough to recursively read through all children until it hits primitives in each object, place each of those objects in the hasp map and return it back.
This is something like the parent would be there in the map. but the individual children also would be there as sub sequent entries in the map.
I am new to java reflection and I went through some tutorials and examples on the net. Not very confident about how to proceed. I believe this is one of the frequent requirements experts and professionals over here might have faced.
Plese help me with a starting point on this. If there is any bean utilities open source available to do this? if so please let me know.
Something like this should do it:
public void fillMap(HashMap<String, Object> map, Object bean) {
try {
BeanInfo info = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] props = info.getPropertyDescriptors();
for (int i = 0; i < props.length; i++) {
Method reader = props[i].getReadMethod();
if (reader != null && !props[i].getName().equals("class")) {
Object invoke = reader.invoke(bean, new Object[] {});
if (invoke != null) {
if (!reader.getReturnType().isPrimitive()) {
fillMap(map, invoke);
} else {
map.put(props[i].getName(), invoke);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
this of course puts all fields from all objects into one map. You might have to create a map for each recursion step if you want submaps for children. I can give you that code as well if you need it.
There is no return of a map, because the one that is passed to the method is filled.
Have a look at Apache Commons BeanUtils. It already does a large chunk of what you need, and may even do the whole lot in one go.

Categories

Resources