0

I am developing a cross platform app that runs on both PC and Android. This app serializes objects and saves them to a file on our server. The issue I am having is that when I deserialize one of the objects on the PC, I get the following error:

java.io.StreamCorruptedException: invalid type code: 71
at java.io.ObjectInputStream.readString(ObjectInputStream.java:1646)
at java.io.ObjectInputStream.readEnum(ObjectInputStream.java:1736)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1990)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1915)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1798)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readArray(ObjectInputStream.java:1706)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1344)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)

however, I can successfully deserialize the object on the Android phone (Samsung s5). This completely baffles me. I have narrowed it down to a platform issue since I have taken the encoded string directly and decoded it on both devices, where an error pops up on the PC and not on the Android device. This suggests to me that the encoded string is not actually corrupt. Am I missing something? Any suggestions would be appreciated.

Here is the code I use to serialize the objects:

public static String objectToString(Serializable object) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        ObjectOutputStream obj = new ObjectOutputStream(out);
        obj.writeObject(object);
        byte[] data = out.toByteArray();
        obj.close();
        out.close();

        return new String(Base64Coder.encode(data));
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

public static Object stringToObject(String encodedObject) {
    try {
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(encodedObject));
        ObjectInputStream input = new ObjectInputStream(bin);
        try{
        return input.readObject();
        }finally{
            Gdx.app.log(TAG, "Input closed!");
            input.close();
            bin.close();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

Also, this the Base64 encoder I use.

eBehbahani
  • 1,579
  • 5
  • 19
  • 41
  • 1
    Dalvik is still [probably](http://stackoverflow.com/questions/4784619/dalvik-to-java-se-communications) not stream compatible with PC JRE. From that question, why not use JSON (or XML)? – Elliott Frisch Apr 28 '14 at 02:08
  • Hmm, I've been using base64 encoding for a while now and haven't had any issues. I could try to change the serialization method but would like to avoid doings so if possible. – eBehbahani Apr 28 '14 at 02:12

2 Answers2

0

You forgot to convert the String to a byte[] to reverse the implicit byte[] to String conversion that happens when executing the new String(Base64Coder.encode(data)).

Try this instead:

public static Object stringToObject(String encodedObject) {
    try {
        byte[] byteArray = encodedObject.getBytes();
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(byteArray));

instead of:

public static Object stringToObject(String encodedObject) {
    try {
        ByteArrayInputStream bin = new ByteArrayInputStream(Base64Coder.decode(encodedObject));
Emanuel Moecklin
  • 28,488
  • 11
  • 69
  • 85
  • The decode method converts the string to a char array (see here: http://www.source-code.biz/base64coder/java/Base64Coder.java.txt). Is that sufficient? – eBehbahani Apr 28 '14 at 15:26
  • You are right. I was assuming the Base64Coder.encode would return an byte[] but it returns a char[] so what I suggest is definitely not necessary. I would check whether Base64Coder.decode(encodedObject) is identical on Android and the PC. If it's identical then Elliott Frisch is probably right. If it's not identical then the Base64 lib has some flaws and I'd try to switch to e.g. the Apache one (http://commons.apache.org/proper/commons-codec). – Emanuel Moecklin Apr 28 '14 at 16:03
  • Another possibility is that encodedObject isn't identical which would mean loading the object from the server is already faulty. If neither the encodedObject nor the decoded base 64 String are different and you absolutely want to stick to Java serialization then you could serialize/deserialize the objects manually (using readObject/writeObject methods). – Emanuel Moecklin Apr 28 '14 at 16:08
  • The encoded objects differ on the PC and on Android, even though the objects are identical. – eBehbahani Apr 28 '14 at 18:48
  • encoded objects = encodedObject (parameter in stringToObject)? – Emanuel Moecklin Apr 28 '14 at 19:47
  • Yes the parameter "encodedObject" is different on both. – eBehbahani Apr 28 '14 at 22:38
  • That means the download of the serialized object already has an issue and you should look into that first. – Emanuel Moecklin Apr 28 '14 at 23:17
0

The problem is that Android up to 7.0 version (API 24) uses Apache Harmony Java implementation, which object serialization format is incompatible with "regular" JRE.

Since Android 7.0 uses OpenJDK and is compatible.

See also:

Ilya Shinkarenko
  • 2,134
  • 18
  • 35