Skip to content

Commit eebea7e

Browse files
committed
Fixed the issue.
1 parent 67c629f commit eebea7e

2 files changed

Lines changed: 64 additions & 24 deletions

File tree

javaobj/v1/unmarshaller.py

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

517-
if classdesc.flags & ClassDescFlags.SC_SERIALIZABLE:
518-
# Handle each class in the hierarchy separately, from most derived to root
519-
self._read_class_data(java_object, classdesc, ident)
517+
# Process class data for the entire hierarchy
518+
self._read_serializable_data(java_object, classdesc, ident)
520519

521520
log_debug(">>> java_object: {0}".format(java_object), ident)
522521
return java_object
523522

524-
def _read_class_data(self, java_object, classdesc, ident):
523+
def _read_serializable_data(self, java_object, classdesc, ident):
525524
"""
526-
Recursively reads class data for the inheritance hierarchy
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
527529
"""
528-
if classdesc is None:
529-
return
530+
if classdesc.superclass:
531+
self._read_serializable_data(java_object, classdesc.superclass, ident + 1)
530532

531-
# First, handle the superclass data
532-
if classdesc.superclass is not None:
533-
self._read_class_data(java_object, classdesc.superclass, ident)
533+
if classdesc.flags & ClassDescFlags.SC_SERIALIZABLE:
534+
# TODO: look at ObjectInputStream.readSerialData()
535+
# FIXME: Handle the SC_WRITE_METHOD flag
536+
537+
log_debug("Constructing class...", ident)
538+
log_debug("Class: {0}".format(classdesc.name), ident + 1)
539+
if classdesc.fields_names:
540+
class_fields_str = " - ".join(
541+
" ".join((str(field_type), field_name))
542+
for field_type, field_name in zip(
543+
classdesc.fields_types, classdesc.fields_names
544+
)
545+
)
546+
log_debug(class_fields_str, ident + 2)
534547

535-
# Then handle this class's data
536-
log_debug("Reading class data for: {0}".format(classdesc.name), ident)
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)
537551

538-
# Read field values for this specific class
539-
for field_name, field_type in zip(classdesc.fields_names, classdesc.fields_types):
540-
log_debug("Reading field: {0} - {1}".format(field_type, field_name), ident)
541-
res = self._read_value(field_type, ident, name=field_name)
542-
java_object.__setattr__(field_name, res)
552+
for field_name, field_type in zip(classdesc.fields_names, classdesc.fields_types):
553+
log_debug(
554+
"Reading field: {0} - {1}".format(field_type, field_name)
555+
)
556+
res = self._read_value(field_type, ident, name=field_name)
557+
java_object.__setattr__(field_name, res)
543558

544-
# Handle annotations if this class has the SC_WRITE_METHOD flag
545-
if classdesc.flags & ClassDescFlags.SC_WRITE_METHOD:
546-
log_debug("Reading annotations for class: {0}".format(classdesc.name), ident)
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:
562+
# objectAnnotation
563+
log_debug(
564+
"java_object.annotations before: {0}".format(
565+
java_object.annotations
566+
),
567+
ident,
568+
)
547569

548-
while True:
570+
opcode = None
571+
while opcode != TerminalCode.TC_ENDBLOCKDATA:
549572
opcode, obj = self._read_and_exec_opcode(ident=ident + 1)
550-
if opcode == TerminalCode.TC_ENDBLOCKDATA:
551-
break
552-
java_object.annotations.append(obj)
573+
# , expect=[self.TC_ENDBLOCKDATA, self.TC_BLOCKDATA,
574+
# self.TC_OBJECT, self.TC_NULL, self.TC_REFERENCE])
575+
if opcode != TerminalCode.TC_ENDBLOCKDATA:
576+
java_object.annotations.append(obj)
577+
553578
log_debug("objectAnnotation value: {0}".format(obj), ident)
554579

580+
log_debug(
581+
"java_object.annotations after: {0}".format(
582+
java_object.annotations
583+
),
584+
ident,
585+
)
586+
587+
# Allow extra loading operations
588+
if hasattr(java_object, "__extra_loading__"):
589+
log_debug("Java object has extra loading capability.")
590+
java_object.__extra_loading__(self, ident)
591+
555592
def do_string(self, parent=None, ident=0):
556593
"""
557594
Handles a TC_STRING opcode

tests/test_v2.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,9 @@ def test_writeObject(self):
645645
self.assertEqual(expected["custom_obj"]["annotations"], super_data)
646646

647647
def test_read_custom(self):
648+
"""
649+
Tests to verify that the super-class is properly read when a custom writer is involved.
650+
"""
648651
ser = self.read_file("issue60_custom_reader_endblock.ser")
649652
pobj = javaobj.loads(ser)
650653
self.assertIsNone(pobj.superItems)

0 commit comments

Comments
 (0)