tcalmant / python-javaobj

Extended fork of python-javaobj from http://code.google.com/p/python-javaobj/
Apache License 2.0
81 stars 19 forks source link

Member fields of type byte[] are serialized as TC_OBJECT instead TC_ARRAY #9

Closed voetsjoeba closed 8 years ago

voetsjoeba commented 8 years ago

While experimenting with the writing functionality of javaobj, I found that when serializing member fields of an object of type byte[], they are written as TC_OBJECTs instead TC_ARRAYs.

Here's a failing test case to reproduce: In tests/java/src/test/java/OneTest.java:

class ClassWithByteArray implements Serializable {
    private static final long serialVersionUID = 1L;
    public byte[] myArray = new byte[]{1,3,7,11};
}
// ...
class OneTest {
    // ...
    @Test
    public void testClassWithByteArray() throws Exception {
        final ClassWithByteArray cwba = new ClassWithByteArray();
        oos.writeObject(cwba);
        oos.flush();
    }
}

In tests/tests.py:

def test_class_with_byte_array_rw(self):
    jobj = self.read_file("testClassWithByteArray.ser")
    pobj = javaobj.loads(jobj)

    self.assertEqual(pobj.myArray, [1,3,7,11])

    jobj_ = javaobj.dumps(pobj)
    self.assertEqual(jobj, jobj_)

The assertEqual at the end fails. Re-reading the result of dumps with loads shows that the myArray field was written as a TC_OBJECT instead of a TC_ARRAY:

...
javaobj: DEBUG: ## New reference handle 0x7E0002: JavaObject -> <javaobj:ClassWithByteArray>
javaobj: DEBUG: Constructing class...
javaobj: DEBUG:   Class: ClassWithByteArray
javaobj: DEBUG:     [B myArray
javaobj: DEBUG: Values count: 1
javaobj: DEBUG: Prepared list of values: ['myArray']
javaobj: DEBUG: Prepared list of types: ['[B']
javaobj: DEBUG: Reading field: [B - myArray
javaobj: DEBUG:   OpCode: 0x73 -- TC_OBJECT (at offset 0x36)
javaobj: DEBUG:   [object]
javaobj: DEBUG:   java_object.annotations just after instantiation: []
javaobj: DEBUG:     OpCode: 0x72 -- TC_CLASSDESC (at offset 0x37)
javaobj: DEBUG:     [classdesc]
javaobj: DEBUG:     Class name: [B
voetsjoeba commented 8 years ago

Adding a missing elif for the JavaArray case to JavaObjectMarshaller._write_value appears to solve the issue, although I can't be sure if that's a good fix since it's also used in other circumstances:

diff --git a/javaobj.py b/javaobj.py
index 38f49d5..25f7b07 100644
--- a/javaobj.py
+++ b/javaobj.py
@@ -1357,6 +1357,8 @@ class JavaObjectMarshaller(JavaObjectConstants):
                 self.write_null()
             elif isinstance(value, JavaEnum):
                 self.write_enum(value)
+            elif isinstance(value, JavaArray):
+                self.write_array(value)
             elif isinstance(value, JavaObject):
                 self.write_object(value)
             elif isinstance(value, JavaString):
tcalmant commented 8 years ago

OK, the bug can be easily reproduced and your fix works as intented. I don't have a real-life usage of this kind of operation (writing arrays) but the specific handling of JavaArray objects was obviously missing.

Do you want to make a pull request with your fix ?

voetsjoeba commented 8 years ago

If you're ok with the fix, sure. Will get one prepared and submitted.

tcalmant commented 8 years ago

PR merged, thanks !