Skip to content

Commit 970d4b2

Browse files
committed
More details in the README file
1 parent 7a92a27 commit 970d4b2

File tree

1 file changed

+112
-25
lines changed

1 file changed

+112
-25
lines changed

README.rst

Lines changed: 112 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ Compatibility warning: New version of the parser
3939

4040
Since version 0.4.0, two implementations of the parser are available:
4141

42-
* `v1`: the *classic* implementation of `javaobj`, with a work in progress
42+
* ``v1``: the *classic* implementation of ``javaobj``, with a work in progress
4343
implementation of a writer.
44-
* `v2`: the *new* implementation, a port of `jdeserialize` with support of the
45-
object transformer (with a new API) and the numpy arrays.
44+
* ``v2``: the *new* implementation, which is a port of the Java project
45+
[``jdeserialize``](https://github.com/frohoff/jdeserialize/),
46+
with support of the object transformer (with a new API) and of the ``numpy``
47+
arrays loading.
4648

4749

4850
Compatibility Warning: object transformer
@@ -88,51 +90,136 @@ Unmarshalling of Java serialised object:
8890

8991
.. code-block:: python
9092
91-
import javaobj
93+
import javaobj
9294
93-
with open("obj5.ser", "rb") as fd:
94-
jobj = fd.read()
95+
with open("obj5.ser", "rb") as fd:
96+
jobj = fd.read()
9597
96-
pobj = javaobj.loads(jobj)
97-
print(pobj)
98+
pobj = javaobj.loads(jobj)
99+
print(pobj)
98100
99-
Or, you can use Unmarshaller object directly:
101+
Or, you can use ``JavaObjectUnmarshaller`` object directly:
100102

101103
.. code-block:: python
102104
103-
import javaobj
105+
import javaobj
104106
105-
with open("objCollections.ser", "rb") as fd:
106-
marshaller = javaobj.JavaObjectUnmarshaller(fd)
107-
pobj = marshaller.readObject()
107+
with open("objCollections.ser", "rb") as fd:
108+
marshaller = javaobj.JavaObjectUnmarshaller(fd)
109+
pobj = marshaller.readObject()
108110
109-
print(pobj.value, "should be", 17)
110-
print(pobj.next, "should be", True)
111+
print(pobj.value, "should be", 17)
112+
print(pobj.next, "should be", True)
111113
112-
pobj = marshaller.readObject()
114+
pobj = marshaller.readObject()
113115
114116
115-
The objects and methods provided by `javaobj` module are shortcuts to the
116-
`javaobj.v1` package
117+
**Note:** The objects and methods provided by ``javaobj`` module are shortcuts
118+
to the ``javaobj.v1`` package, for Compatibility purpose.
119+
It is **recommended** to explicitly import methods and classes from the ``v1``
120+
(or ``v2``) package when writing new code, in order to be sure that your code
121+
won't need import updates in the future.
117122

118123

119124
Usage (V2 implementation)
120125
=========================
121126

122-
Unmarshalling of Java serialised object:
127+
The following methods are provided by the ``javaobj.v2`` package:
128+
129+
* ``load(fd, *transformers, use_numpy_arrays=False)``:
130+
Parses the content of the given file descriptor, opened in binary mode (`rb`).
131+
The method accepts a list of custom object transformers. The default object
132+
transformer is always added to the list.
133+
134+
The ``use_numpy_arrays`` flag indicates that the arrays of primitive type
135+
elements must be loaded using ``numpy`` (if available) instead of using the
136+
standard parsing technic.
137+
138+
* ``loads(bytes, *transformers, use_numpy_arrays=False)``:
139+
This the a shortcut to the ``load()`` method, providing it the binary data
140+
using a ``BytesIO`` object.
141+
142+
**Note:** The V2 parser doesn't have the marshalling capability.
143+
144+
Sample usage:
123145

124146
.. code-block:: python
125147
126-
import javaobj.v2 as javaobj
148+
import javaobj.v2 as javaobj
127149
128-
with open("obj5.ser", "rb") as fd:
129-
jobj = fd.read()
150+
with open("obj5.ser", "rb") as fd:
151+
pobj = javaobj.load(fd)
130152
131-
pobj = javaobj.loads(jobj)
132-
print(pobj)
153+
print(pobj.dump())
133154
134155
135156
Object Transformer
136157
-------------------
137158

138-
WIP
159+
An object transformer can be called during the parsing of a Java object
160+
instance or while loading an array.
161+
162+
The Java object instance parsing works in two main steps:
163+
164+
1. The transformer is called to create an instance of a bean that inherits
165+
``JavaInstance``.
166+
2. The latter bean is then called:
167+
* When the object is written with a custom block data
168+
* After the fields and annotations have been parsed, to update the content of
169+
the Python bean.
170+
171+
Here is an example for a Java ``HashMap`` object. You can look at the code of
172+
the ``javaobj.v2.transformer`` module to see the whole implementation.
173+
174+
.. code-block:: python
175+
176+
class JavaMap(dict, javaobj.v2.beans.JavaInstance):
177+
"""
178+
Inherits from dict for Python usage, JavaInstance for parsing purpose
179+
"""
180+
def __init__(self):
181+
# Don't forget to call both constructors
182+
dict.__init__(self)
183+
JavaInstance.__init__(self)
184+
185+
def load_from_instance(self, instance, indent=0):
186+
# type: (JavaInstance, int) -> bool
187+
"""
188+
Load content from a parsed instance object
189+
190+
:param instance: The currently loaded instance
191+
:param indent: Indentation to use while logging
192+
:return: True on success
193+
"""
194+
# Maps have their content in their annotations
195+
for cd, annotations in instance.annotations.items():
196+
# Annotations are associated to their definition class
197+
if cd.name == "java.util.HashMap":
198+
# We are in the annotation created by the handled class
199+
# Group annotation elements 2 by 2
200+
# (storage is: key, value, key, value, ...)
201+
args = [iter(annotations[1:])] * 2
202+
for key, value in zip(*args):
203+
self[key] = value
204+
205+
# Job done
206+
return True
207+
208+
# Couldn't load the data
209+
return False
210+
211+
class MapObjectTransformer(javaobj.v2.api.ObjectTransformer):
212+
def create_instance(self, classdesc):
213+
# type: (JavaClassDesc) -> Optional[JavaInstance]
214+
"""
215+
Transforms a parsed Java object into a Python object
216+
217+
:param classdesc: The description of a Java class
218+
:return: The Python form of the object, or the original JavaObject
219+
"""
220+
if classdesc.name == "java.util.HashMap":
221+
# We can handle it
222+
return JavaMap()
223+
else:
224+
# Return None if not handled
225+
return None

0 commit comments

Comments
 (0)