2

i'm trying to serialize a HashMap on serverside(Tomcat 6.0.29) and to deserealize it on a client-side android application.

First time i've tried this i got an StreamCorruptedException, but after i created a completly new servlet with a clean doGet/doPost-Method i've managed to solve this issue, unfortunatly i get an EOFException instead.

So first i'm posting my code and then i'll explain my problem in detail:

Server-Side Code (this will be executed when doPost Or doGet is invoked):

    if ("object".equals(request.getParameter("format")))
        {

            trace.log("Before Serializing");
            ObjectOutputStream out = null;
            try
            {
                out = new ObjectOutputStream(response.getOutputStream());
                out.writeObject(outerTable);
                trace.log("after Serializing");
            }
            finally
            {
                if(out != null)
                {
                    try
                    {
                        out.flush();
                        out.close();
                    }
                    catch(Exception ex)
                    {
                        trace.log("Exception has been thrown "+ex.getMessage());
                    }
                }
            }
            trace.log("after closing stream");
        }
        else
        {
            PrintWriter out = response.getWriter();
            out.println(outerTable.toString());
        }

outerTable is a HashMap wich is created exactly before this code-block and it has always correct values.

There are no errors thrown on server-side. When i try to access the servlet in my webbrowser with parameter "?format=object" i get the whole serialization string.

Script of Android-Application (this Method executes the http request after a specific button is pressed):

    private synchronized void performNetworkAccess()
    {
  Runnable run = new Runnable()
  {
    @Override
    public void run()
    {
    System.out.println("in run()-Method");
    ObjectInputStream objInput = null;
    try
    {
        URL url = new URL(myWebsite);
        URLConnection con = url.openConnection();
        InputStream in = con.getInputStream(); 
        objInput = new ObjectInputStream(in);

        outerTable = (HashMap<String, HashMap<String, Object>>)              objInput.readObject();
        synchronized (monitor)
        {
        monitor.notifyAll();
        }
    }
    catch (Exception ex)
    {
        ex.printStackTrace();
    }
    finally
    {
        if (objInput != null)
        {
        try
        {
            objInput.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        }
    }

    }

};
Thread t1 = new Thread(run);
t1.start();
}

The Exception occurs immediatly after the constructor of ObjectInputStream class is invoked.

Stacktrace:

  • W/System.err(1797): java.io.EOFException
  • W/System.err(1797): at libcore.io.Streams.readFully(Streams.java:83)
  • W/System.err(1797): at java.io.DataInputStream.readShort(DataInputStream.java:169)
  • W/System.err(1797): at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:2102)
  • W/System.err(1797): at java.io.ObjectInputStream.(ObjectInputStream.java:372)
  • W/System.err(1797): at de.tesla.jtheseuscontactsync.ContactSync$4.run(ContactSync.java:602)
  • W/System.err(1797): at java.lang.Thread.run(Thread.java:856)

I've already found many occurences of this problem, but i didn't see one of them where this error occures before readObject() is invoked.

Things i've already tried:

  • add out.flush() shortly after constructing ObjectOutputStream
  • remove out.flush() and/or out.close() method(s)
  • wrap Input-/OutputStream with BufferedInput-/-OutputStream
  • retrieve stream as a file and try to deserealize the file

The odd thing is when i first write the Object to a file via FileOutputStream and access this file (on the server) from the client via Url.openStream() then ObjectOutputStream can read this object perfectly, unfortunatly this would mean a lot of trouble when multiple users trying to retrieve this object at the same time...

i hope you can help me out with this one :)

4
  • 1
    A serialized Java object as it is created by an ObjectOutputStream can only be deserialized in an environment that uses an identical implementation. Even changing the JRE version can prevent a deserialization. Therefore using serialization to transfer data in a complex non-self-written object structure is a very bad idea. Commented Sep 18, 2012 at 14:11
  • Indeed I was going to answer that, but I saw that deserialization worked when done from a file... so changed my post :) Commented Sep 18, 2012 at 14:15
  • 1
    @Robert That is completely incorrect. The Java Serialization mechanism s compatible with every JRE all the way back to Java 1.1. Commented Feb 7, 2017 at 17:02
  • 1
    @EJP the mechanism is well defined, but not the classes that belong to the JRE. The serialization contains data on private fields which are never described in the Java API, therefore serialization may fail, especially when using different Java runtime environments (e.g. Oracle JRE, Android, ...). Anyway Java serialization creates bloated data and is highly insecure. Commented Feb 7, 2017 at 18:13

2 Answers 2

0

The servlet has got an exception of some kind and hasn't even constructed the ObjectOutputStream. You need to check the response code for 200 before you try to construct the ObjectInputStream at the client.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the advice this is indeed a value worth to be checked before %)
-2

Some crazy idea... try to add a Content-Length header to your response. Could imply writing your bytes to a ByteArrayOutputStream, measuring the size, setting the header and only then writing to response... but could be the reason that URLConnection is prematurely cutting the connection...

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObejctOutputStream oos = new ObejctOutputStream(baos);
oos.write(...);

byte[] data = baos.toByteArray();

response.setHeader("Content-Length", "" + data.length);
response.getOutputStream().write(data);

Java Serialization

@Robert comment is right. Java serialization is not intented for communication between different environments. More if you're working between JVM and Dalvik. So another framework would be more suitable (something with XML or JSON could be nice, even wrapping it with a GZip[]Stream).

3 Comments

The servlet container already does exactly that. No point in doing it again.
@EJP the servlet container add content-length header? based on response body actual size? If it does it should buffer the entire response... and that doesn't seem a nice default behaviour...
Well... great! I'm a little bit surprised, but glad! In any case if things are explicit (explicit content-length), better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.