13

I need serialize objects into String and deserialize.

I readed sugestion on stackoverflow and make this code:

class Data implements Serializable {
int x = 5;
int y = 3;   
}

public class Test {
public static void main(String[] args) {

    Data data = new Data();

    String out;

    try {
        // zapis
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);

        oos.writeObject(data);

        out = new String(baos.toByteArray());
        System.out.println(out);

        // odczyt.==========================================

        ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());

        ObjectInputStream ois = new ObjectInputStream(bais);

        Data d = (Data) ois.readObject();

        System.out.println("d.x = " + d.x);
        System.out.println("d.y = " + d.y);

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

}

}

but I get error:

java.io.StreamCorruptedException: invalid stream header: EFBFBDEF
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:801)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:298)
at p.Test.main(Test.java:37)

Why? I expected: d.x = 5 d.y = 3

how to do in good way? Ah. I don't want to write this object in file. I have to have it in string format.

4
  • 1
    Why exactly do you want to store a binary representation in a String in the first place ? Why not just keep it as a byte array or something ?... Commented Nov 26, 2012 at 16:03
  • @CostiCiudatu beacuse I have to write a method which store objects into sqlite database but part in sqlite is not depend on me. And there is text column. Now I have xml serialization but it is slow. I need fast way. Commented Nov 27, 2012 at 7:04
  • Did you check if SQLite supports something like BLOB for storing raw bytes ? Commented Nov 27, 2012 at 7:09
  • @CostiCiudatu Sqlite support BLOB but how it can help me? Commented Nov 27, 2012 at 8:32

2 Answers 2

11

Use
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); instead of ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());, since the String conversion corrupts the data (because of the encoding).

If you really need to store the result in a String, you need a safe way to store arbitrary bytes in a String. One way of doing that is to us Base64-encoding.

A totally different approach would have been to not use the standard Java serialization for this class, but create your own Data to/from String converter.

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

3 Comments

+1 don't forget to close the stream as well as its buffered. ;)
Base64 slowed this problem. :)
Thanks, I should have known this was an encoding issue. In my case I needed to use org.apache.tomcat.util.codec.binary.Base64 with Base64.encodeBase64String to create the string and Base64.decodeBase64 to decode it.
11

It is not entirely true to say that conversion to string corrupts the data. Conversion to "UTF-8" does because it is not bijective (some characters are 2 bytes but not all 2 bytes sequences are allowed as character sequences), while "ISO-8859-1" is bijective (1 character of a String is a byte and vice-versa).

Base64 encoding is not very space-efficient compared to this.

This is why I would recommend:

/**
 * Serialize any object
 * @param obj
 * @return
 */
public static String serialize(Object obj) {
    try {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream so = new ObjectOutputStream(bo);
        so.writeObject(obj);
        so.flush();
        // This encoding induces a bijection between byte[] and String (unlike UTF-8)
        return bo.toString("ISO-8859-1");
    } catch (Exception e) {
        e.printStackTrace();
    }
}
/**
 * Deserialize any object
 * @param str
 * @param cls
 * @return
 */
public static <T> T deserialize(String str, Class<T> cls) {
    // deserialize the object
    try {
        // This encoding induces a bijection between byte[] and String (unlike UTF-8)
        byte b[] = str.getBytes("ISO-8859-1"); 
        ByteArrayInputStream bi = new ByteArrayInputStream(b);
        ObjectInputStream si = new ObjectInputStream(bi);
        return cls.cast(si.readObject());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

1 Comment

How can you be sure that the binary representation can be converted to String? For instance, how can the String terminator character (usually \0 in C) be converted to a valid character inside the String? The answer is, you can't. For that reason we should convert the byte array to a safe textual representation, such as Base64.

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.