• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tcalmant / python-javaobj / 26725741611

31 May 2026 10:02PM UTC coverage: 78.709% (+0.008%) from 78.701%
26725741611

Pull #63

github

web-flow
Merge 0786da843 into 519fc2167
Pull Request #63: Addition of a v3 package

808 of 1023 new or added lines in 7 files covered. (78.98%)

2403 of 3053 relevant lines covered (78.71%)

2.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.55
/javaobj/v3/__init__.py
1
#!/usr/bin/env python3
2
"""
3
Rewritten version of the un-marshalling process of javaobj (v3)
4

5
This package targets Python 3.12+ and provides fully typed parsing of the
6
Java Object Serialization stream format, in read-only mode.
7

8
:authors: Thomas Calmant
9
:license: Apache License 2.0
10
:version: 0.5.0
11
:status: Alpha
12

13
..
14

15
    Copyright 2026 Thomas Calmant
16

17
    Licensed under the Apache License, Version 2.0 (the "License");
18
    you may not use this file except in compliance with the License.
19
    You may obtain a copy of the License at
20

21
        http://www.apache.org/licenses/LICENSE-2.0
22

23
    Unless required by applicable law or agreed to in writing, software
24
    distributed under the License is distributed on an "AS IS" BASIS,
25
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
26
    See the License for the specific language governing permissions and
27
    limitations under the License.
28
"""
29

30
# Standard library
31
from io import BytesIO
3✔
32
from typing import IO, Any
3✔
33

34
# Javaobj
35
from ..utils import java_data_fd
3✔
36

37
# Also expose the beans sub-module so that ``javaobj.v3.beans.JavaInstance``
38
# works out of the box (same pattern as v2).
39
from . import beans  # noqa: F401
3✔
40
from .beans import (
3✔
41
    BlockData,
42
    ClassDataType,
43
    ClassDescType,
44
    ExceptionState,
45
    FieldType,
46
    JavaArray,
47
    JavaClass,
48
    JavaClassDesc,
49
    JavaEnum,
50
    JavaField,
51
    JavaInstance,
52
    JavaString,
53
    ParsedContent,
54
)
55
from .exceptions import (
3✔
56
    JavaObjError,
57
    ParseError,
58
    SecurityError,
59
    UnexpectedOpcodeError,
60
    UnsupportedFeatureError,
61
)
62
from .parser import JavaStreamParser
3✔
63
from .reader import DataReader
3✔
64
from .transformers import (
3✔
65
    DefaultObjectTransformer,
66
    NumpyArrayTransformer,
67
    ObjectTransformer,
68
)
69

70
__all__ = [
3✔
71
    # Entry points
72
    "load",
73
    "loads",
74
    # Transformer API
75
    "ObjectTransformer",
76
    "DefaultObjectTransformer",
77
    "NumpyArrayTransformer",
78
    # Bean types
79
    "JavaInstance",
80
    "JavaArray",
81
    "JavaString",
82
    "JavaEnum",
83
    "JavaClass",
84
    "JavaClassDesc",
85
    "JavaField",
86
    "BlockData",
87
    "ExceptionState",
88
    "FieldType",
89
    "ClassDataType",
90
    "ClassDescType",
91
    "ParsedContent",
92
    # Parser
93
    "JavaStreamParser",
94
    "DataReader",
95
    # Exceptions
96
    "JavaObjError",
97
    "ParseError",
98
    "UnexpectedOpcodeError",
99
    "UnsupportedFeatureError",
100
    "SecurityError",
101
]
102

103
# ------------------------------------------------------------------------------
104

105
# Module version
106
__version_info__ = (0, 5, 0)
3✔
107
__version__ = ".".join(str(x) for x in __version_info__)
3✔
108

109
# Documentation strings format
110
__docformat__ = "restructuredtext en"
3✔
111

112
# ------------------------------------------------------------------------------
113
# Public API
114
# ------------------------------------------------------------------------------
115

116

117
def load(
3✔
118
    file_object: IO[bytes],
119
    *transformers: ObjectTransformer,
120
    use_numpy_arrays: bool = False,
121
    max_array_size: int = DataReader.DEFAULT_MAX_ARRAY_SIZE,
122
    max_depth: int = DataReader.DEFAULT_MAX_DEPTH,
123
) -> Any:
124
    """
125
    Deserializes Java object(s) from a binary file-like object.
126

127
    The stream is automatically decompressed if it is GZip-compressed.
128

129
    :param file_object: A readable binary stream containing a Java serialized
130
                        object stream (magic ``0xACED 0x0005``).
131
    :param transformers: Zero or more custom :class:`ObjectTransformer`
132
                         instances.  A :class:`DefaultObjectTransformer` is
133
                         always added unless one is already present.
134
    :param use_numpy_arrays: When ``True`` and *numpy* is installed, primitive
135
                             arrays are loaded as ``numpy.ndarray`` objects.
136
    :param max_array_size: Maximum bytes for a single array allocation.
137
    :param max_depth: Maximum object-graph recursion depth.
138
    :return: The parsed object if the stream contains exactly one top-level
139
             object, or a list of objects if there are several.
140
             Returns ``None`` for an empty stream.
141
    :raises ParseError: If the stream is malformed.
142
    :raises SecurityError: If a safety limit is exceeded.
143
    :raises UnsupportedFeatureError: If an unsupported protocol feature is
144
                                     encountered.
145
    """
146
    # Auto-decompress GZip streams
147
    fd = java_data_fd(file_object)
3✔
148

149
    # Build transformer list, ensuring DefaultObjectTransformer is present
150
    all_transformers: list[ObjectTransformer] = list(transformers)
3✔
151
    if not any(isinstance(t, DefaultObjectTransformer) for t in all_transformers):
3✔
152
        all_transformers.append(DefaultObjectTransformer())
3✔
153

154
    if use_numpy_arrays:
3✔
NEW
155
        all_transformers.append(NumpyArrayTransformer())
×
156

157
    parser = JavaStreamParser(
3✔
158
        fd,
159
        all_transformers,
160
        max_array_size=max_array_size,
161
        max_depth=max_depth,
162
    )
163
    contents = parser.run()
3✔
164

165
    if not contents:
3✔
166
        return None
3✔
167
    if len(contents) == 1:
3✔
168
        return contents[0]
3✔
169
    return contents
3✔
170

171

172
def loads(
3✔
173
    data: bytes,
174
    *transformers: ObjectTransformer,
175
    use_numpy_arrays: bool = False,
176
    max_array_size: int = DataReader.DEFAULT_MAX_ARRAY_SIZE,
177
    max_depth: int = DataReader.DEFAULT_MAX_DEPTH,
178
) -> Any:
179
    """
180
    Deserializes Java object(s) from a :class:`bytes` object.
181

182
    :param data: Raw bytes of a Java serialized stream.
183
    :param transformers: Optional custom transformers (see :func:`load`).
184
    :param use_numpy_arrays: See :func:`load`.
185
    :param max_array_size: See :func:`load`.
186
    :param max_depth: See :func:`load`.
187
    :return: Parsed object or list of objects (see :func:`load`).
188
    """
189
    return load(
3✔
190
        BytesIO(data),
191
        *transformers,
192
        use_numpy_arrays=use_numpy_arrays,
193
        max_array_size=max_array_size,
194
        max_depth=max_depth,
195
    )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc