Skip to content

Commit 68eeb66

Browse files
authored
Merge pull request #61 from svaningelgem/fix-for-custom-reader
fix: Custom reader should read till endblock
2 parents 8266d68 + 1bf2a23 commit 68eeb66

5 files changed

Lines changed: 111 additions & 36 deletions

File tree

javaobj/v1/unmarshaller.py

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -514,56 +514,51 @@ def do_object(self, parent=None, ident=0):
514514
# TODO:
515515
raise NotImplementedError("externalContents isn't implemented yet")
516516

517+
# Process class data for the entire hierarchy
518+
self._read_serializable_data(java_object, classdesc, ident)
519+
520+
log_debug(">>> java_object: {0}".format(java_object), ident)
521+
return java_object
522+
523+
def _read_serializable_data(self, java_object, classdesc, ident):
524+
"""
525+
Read serializable data following the Java specification more closely.
526+
According to the spec, for each class in the hierarchy (from super to sub):
527+
1. Read primitive fields
528+
2. If SC_WRITE_METHOD is set, read custom writeObject data until TC_ENDBLOCKDATA
529+
"""
530+
if classdesc.superclass:
531+
self._read_serializable_data(java_object, classdesc.superclass, ident + 1)
532+
517533
if classdesc.flags & ClassDescFlags.SC_SERIALIZABLE:
518534
# TODO: look at ObjectInputStream.readSerialData()
519535
# FIXME: Handle the SC_WRITE_METHOD flag
520536

521-
# create megalist
522-
tempclass = classdesc
523-
megalist = []
524-
megatypes = []
525537
log_debug("Constructing class...", ident)
526-
while tempclass:
527-
log_debug("Class: {0}".format(tempclass.name), ident + 1)
538+
log_debug("Class: {0}".format(classdesc.name), ident + 1)
539+
if classdesc.fields_names:
528540
class_fields_str = " - ".join(
529541
" ".join((str(field_type), field_name))
530542
for field_type, field_name in zip(
531-
tempclass.fields_types, tempclass.fields_names
543+
classdesc.fields_types, classdesc.fields_names
532544
)
533545
)
534-
if class_fields_str:
535-
log_debug(class_fields_str, ident + 2)
536-
537-
fieldscopy = tempclass.fields_names[:]
538-
fieldscopy.extend(megalist)
539-
megalist = fieldscopy
546+
log_debug(class_fields_str, ident + 2)
540547

541-
fieldscopy = tempclass.fields_types[:]
542-
fieldscopy.extend(megatypes)
543-
megatypes = fieldscopy
548+
log_debug("Values count: {0}".format(len(classdesc.fields_names)), ident)
549+
log_debug("Prepared list of values: {0}".format(classdesc.fields_names), ident)
550+
log_debug("Prepared list of types: {0}".format(classdesc.fields_types), ident)
544551

545-
tempclass = tempclass.superclass
546-
547-
log_debug("Values count: {0}".format(len(megalist)), ident)
548-
log_debug("Prepared list of values: {0}".format(megalist), ident)
549-
log_debug("Prepared list of types: {0}".format(megatypes), ident)
550-
551-
for field_name, field_type in zip(megalist, megatypes):
552+
for field_name, field_type in zip(classdesc.fields_names, classdesc.fields_types):
552553
log_debug(
553554
"Reading field: {0} - {1}".format(field_type, field_name)
554555
)
555556
res = self._read_value(field_type, ident, name=field_name)
556557
java_object.__setattr__(field_name, res)
557558

558-
if (
559-
classdesc.flags & ClassDescFlags.SC_SERIALIZABLE
560-
and classdesc.flags & ClassDescFlags.SC_WRITE_METHOD
561-
or classdesc.flags & ClassDescFlags.SC_EXTERNALIZABLE
562-
and classdesc.flags & ClassDescFlags.SC_BLOCK_DATA
563-
or classdesc.superclass is not None
564-
and classdesc.superclass.flags & ClassDescFlags.SC_SERIALIZABLE
565-
and classdesc.superclass.flags & ClassDescFlags.SC_WRITE_METHOD
566-
):
559+
has_write_method = classdesc.flags & ClassDescFlags.SC_SERIALIZABLE and classdesc.flags & ClassDescFlags.SC_WRITE_METHOD
560+
has_block_data = classdesc.flags & ClassDescFlags.SC_EXTERNALIZABLE and classdesc.flags & ClassDescFlags.SC_BLOCK_DATA
561+
if has_write_method or has_block_data:
567562
# objectAnnotation
568563
log_debug(
569564
"java_object.annotations before: {0}".format(
@@ -572,6 +567,7 @@ def do_object(self, parent=None, ident=0):
572567
ident,
573568
)
574569

570+
opcode = None
575571
while opcode != TerminalCode.TC_ENDBLOCKDATA:
576572
opcode, obj = self._read_and_exec_opcode(ident=ident + 1)
577573
# , expect=[self.TC_ENDBLOCKDATA, self.TC_BLOCKDATA,
@@ -593,9 +589,6 @@ def do_object(self, parent=None, ident=0):
593589
log_debug("Java object has extra loading capability.")
594590
java_object.__extra_loading__(self, ident)
595591

596-
log_debug(">>> java_object: {0}".format(java_object), ident)
597-
return java_object
598-
599592
def do_string(self, parent=None, ident=0):
600593
"""
601594
Handles a TC_STRING opcode
175 Bytes
Binary file not shown.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import java.io.*;
2+
import java.util.List;
3+
4+
class SuperClass implements Serializable {
5+
private List<String> superItems = null;
6+
7+
private void writeObject(ObjectOutputStream out) throws IOException {
8+
out.defaultWriteObject();
9+
// Custom serialization logic that triggers SC_WRITE_METHOD flag
10+
out.writeUTF("custom_marker");
11+
}
12+
13+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
14+
in.defaultReadObject();
15+
// Custom deserialization logic
16+
String marker = in.readUTF();
17+
System.out.println("Read custom marker: " + marker);
18+
}
19+
}
20+
21+
class CustomClass extends SuperClass {
22+
private static final long serialVersionUID = 1L;
23+
24+
private String name;
25+
private List<String> items = null;
26+
private int port = 443;
27+
28+
public CustomClass(String name) {
29+
this.name = name;
30+
}
31+
32+
private void writeObject(ObjectOutputStream out) throws IOException {
33+
out.defaultWriteObject();
34+
// Custom serialization for child class too
35+
out.writeInt(42);
36+
}
37+
38+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
39+
in.defaultReadObject();
40+
int customValue = in.readInt();
41+
System.out.println("Read custom value: " + customValue);
42+
}
43+
44+
@Override
45+
public String toString() {
46+
return "CustomClass{name='" + name + "', items=" + items + "', port=" + port + "}";
47+
}
48+
}
49+
50+
public class SerializationExample {
51+
public static void main(String[] args) {
52+
try {
53+
// Create and serialize
54+
CustomClass obj = new CustomClass("test");
55+
System.out.println("Original: " + obj);
56+
57+
// Serialize to file
58+
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("issue60_custom_reader_endblock.ser"))) {
59+
oos.writeObject(obj);
60+
}
61+
62+
// Deserialize from file
63+
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("issue60_custom_reader_endblock.ser"))) {
64+
CustomClass deserialized = (CustomClass) ois.readObject();
65+
System.out.println("Deserialized: " + deserialized);
66+
}
67+
68+
} catch (IOException | ClassNotFoundException e) {
69+
e.printStackTrace();
70+
}
71+
}
72+
}

tests/test_v1.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,17 @@ def test_qistoph_pr_27(self):
508508
for key, value in pobj.items():
509509
self.assertEqual(parent_map[key], value)
510510

511+
def test_read_custom(self):
512+
"""
513+
Tests to verify that the super-class is properly read when a custom writer is involved.
514+
"""
515+
ser = self.read_file("issue60_custom_reader_endblock.ser")
516+
pobj = javaobj.loads(ser)
517+
self.assertIsNone(pobj.superItems)
518+
self.assertIsNone(pobj.items)
519+
self.assertEquals(pobj.name, "test")
520+
self.assertEquals(pobj.port, 443)
521+
511522

512523
# ------------------------------------------------------------------------------
513524

tests/test_v2.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,6 @@ def test_writeObject(self):
644644
self.assertEqual(expected["custom_obj"]["field_data"], child_data)
645645
self.assertEqual(expected["custom_obj"]["annotations"], super_data)
646646

647-
648647
# ------------------------------------------------------------------------------
649648

650649

0 commit comments

Comments
 (0)