ObjectInputStream vs DataInputStream

Can someone describe the difference between those 2 different types, because in my code, I used ObjectInputStream and the entire program just hung there. However, when i used DataInputStream, it didn’t hang, but i can no longer use the readObject method. Can someone offer maybe some suggestions for a solution?

I think the javadoc for them makes it very clear what the difference is, as does your experience using them. They’re not interchangeable. You may need to go in with a debugger or sprinkle logging statements around your code to determine where things are hanging.

I had determined that where I create the ObjectInputStream was where the program was hanging, but a had no idea why.

Paste the code that’s hanging (use [ code ] tags) and we can take a look.

Socket connection = server.accept();
		System.out.println(connection);
		connections.add(connection);
		System.out.println("Connection recieved from " + connection.getInetAddress().getHostName());
		
		ObjectInputStream input = new ObjectInputStream(connection.getInputStream());
		System.out.println("input established");
		
		ObjectOutputStream output = new ObjectOutputStream(connection.getOutputStream());
		System.out.println("output established");
		output.flush();

it gets to the line where it creates ‘input’ and it doesn’t go any further than that.

So you get the “Connection received” message, but not the “input established” message? That is curious … to my knowledge there’s nothing about constructing an OIS that should be inherently be blocking, only reading it. Maybe Socket.getInputStream() is doing it, try breaking that out into another line with its own debug line.

Ok, i did what you said, and it doesn’t seem to be a problem with Socket.getInputStream(). This is what i have now, with the line broken up.


                Socket connection = server.accept();
		System.out.println(connection);
		connections.add(connection);
		System.out.println("Connection recieved from " + connection.getInetAddress().getHostName());
		
		InputStream is = connection.getInputStream();
		System.out.println("InputStream created");
		
		
		ObjectInputStream input = new ObjectInputStream(is);
		System.out.println("input established");
		
		ObjectOutputStream output = new ObjectOutputStream(connection.getOutputStream());
		System.out.println("output established");
		output.flush();

Just like GZipInputStream, ObjectInputSteam does I/O in the constructor (which is aweful).


    public ObjectInputStream(InputStream in) throws IOException {
        verifySubclass();
        bin = new BlockDataInputStream(in);
        handles = new HandleTable(10);
        vlist = new ValidationList();
        enableOverride = false;
@@        readStreamHeader();
        bin.setBlockDataMode(true);
    }

    public GZIPInputStream(InputStream in, int size) throws IOException {
        super(in, new Inflater(true), size);
        usesDefaultInflater = true;
@@        readHeader(in);
    }

There are two awkward solutions…
[x] Creating an ObjectInputStream wrapper, that defers the I/O to the first read
[x] Creating an ObjectInputStream on its own thread.

I had just ass-u-me’d that java.io was actually, well, sane. Anyway, as long as the other end sends an object eventually, you should be fine.

Well, i’ve just set it up so that it creates the Output first and flushes it, AND THEN creates the input and it seems to be working just fine. Thanks for all the help guys.

Something like:


class LazyObjectInputStream extends DataInputStream
{
   private final DataInputStream dis;
   private ObjectInputStream ois;

   public LazyObjectInputStream(DataInputStream dis) {
      this.dis = dis;
      this.ois = null;
   }

   private boolean inited;
   private void ensureInited() throws IOException {
      if(inited) {
         return;
      }
      inited = true;

      ios = new ObjectInputStream(dis);
   }

   public int read() throws IOException {
      this.ensureInited();
      return ios.read();
   }

   public int read(byte[] b) throws IOException {
      this.ensureInited();
      return ios.read(b);
   }

   public int read(byte[] b, int off, int len) throws IOException {
      this.ensureInited();
      return ios.read(b, off, len);
   }

   public Object readObject() throws IOException {
      this.ensureInited();
      return ios.readObject();
   }

   public void close() throws IOException {
      if(ios==null) {
         dis.close();
      }
      else {
         ois.close();
      }
   }
}

because you really, really want to do I/O on your own terms. :cranky: