├── .gitignore
├── obj0.ser
├── obj1.ser
├── obj2.ser
├── obj3.ser
├── obj4.ser
├── obj5.ser
├── obj6.ser
├── obj7.ser
├── objArrays.ser
├── objEnums.ser
├── objSuper.ser
├── sunExample.ser
├── objCollections.ser
├── objException.ser
├── java
├── pom.xml
└── src
│ └── test
│ └── java
│ ├── CollectionsTest.java
│ ├── JFrameTest.java
│ └── OneTest.java
├── setup.py
├── README.md
├── tests.py
├── LICENSE
└── javaobj.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__
2 | *.pyc
3 |
--------------------------------------------------------------------------------
/obj0.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj0.ser
--------------------------------------------------------------------------------
/obj1.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj1.ser
--------------------------------------------------------------------------------
/obj2.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj2.ser
--------------------------------------------------------------------------------
/obj3.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj3.ser
--------------------------------------------------------------------------------
/obj4.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj4.ser
--------------------------------------------------------------------------------
/obj5.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj5.ser
--------------------------------------------------------------------------------
/obj6.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj6.ser
--------------------------------------------------------------------------------
/obj7.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/obj7.ser
--------------------------------------------------------------------------------
/objArrays.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/objArrays.ser
--------------------------------------------------------------------------------
/objEnums.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/objEnums.ser
--------------------------------------------------------------------------------
/objSuper.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/objSuper.ser
--------------------------------------------------------------------------------
/sunExample.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/sunExample.ser
--------------------------------------------------------------------------------
/objCollections.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/objCollections.ser
--------------------------------------------------------------------------------
/objException.ser:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vbuell/python-javaobj/HEAD/objException.ser
--------------------------------------------------------------------------------
/java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.python-javaobj
8 | python-javaobj
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 |
14 | junit
15 | junit
16 | 4.9
17 | test
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | from setuptools import setup
3 |
4 | setup(
5 | name="javaobj",
6 | version="0.1.0",
7 | author="Volodymyr Buell",
8 | author_email="vbuell@gmail.com",
9 | url="http://code.google.com/p/python-javaobj",
10 | description=("Module for serializing and de-serializing Java objects."),
11 | license="APL2",
12 | keywords="python java marshalling serialization",
13 | # packages=['javaobj'],
14 | py_modules = ['javaobj'],
15 | test_suite = "tests",
16 | long_description="Provides functions for reading and writing (writing is WIP currently) " \
17 | "Java objects serialized or will be deserialized by ObjectOutputStream. " \
18 | "This form of object representation is a standard data interchange format " \
19 | "in Java world. javaobj module exposes an API familiar to users of the " \
20 | "standard library marshal, pickle and json modules.",
21 | classifiers=[
22 | "Development Status :: 3 - Alpha",
23 | "License :: OSI Approved :: Apache Software License",
24 | "Topic :: Software Development :: Libraries :: Python Modules",
25 | ],
26 | )
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # python-javaobj
2 |
3 | python-javaobj is a python library that provides functions for reading and writing (writing is WIP currently) Java objects
4 | serialized or will be deserialized by _ObjectOutputStream_. This form of object
5 | representation is a standard data interchange format in Java world.
6 |
7 | javaobj module exposes an API familiar to users of the standard library marshal, pickle and json modules.
8 |
9 | ## Features
10 |
11 | * Java object instance unmarshaling
12 | * Java classes unmarshaling
13 | * Primitive values unmarshaling
14 | * Automatic conversion of Java Collections to python ones (_HashMap_ => dict, _ArrayList_ => list, etc)
15 |
16 | ## Requirements
17 |
18 | * Python >= 2.6, but < 3.0 (porting to 3.0 is in progress)
19 | * Maven 2+ (for building test data of serialized objects. You can skip it if you do not plan to run tests.py)
20 |
21 | ## Usage
22 |
23 | Unmarshalling of Java serialised object:
24 |
25 | ```python
26 | import javaobj
27 |
28 | jobj = self.read_file("obj5.ser")
29 | pobj = javaobj.loads(jobj)
30 | print pobj
31 | ```
32 |
33 | Or, you can use Unmarshaller object directly:
34 |
35 | ```python
36 | import javaobj
37 |
38 | marshaller = javaobj.JavaObjectUnmarshaller(open("sunExample.ser"))
39 | pobj = marshaller.readObject()
40 |
41 | self.assertEqual(pobj.value, 17)
42 | self.assertTrue(pobj.next)
43 |
44 | pobj = marshaller.readObject()
45 | ```
46 |
--------------------------------------------------------------------------------
/java/src/test/java/CollectionsTest.java:
--------------------------------------------------------------------------------
1 | import java.io.FileOutputStream;
2 | import java.io.ObjectOutputStream;
3 | import java.io.Serializable;
4 | import java.util.ArrayList;
5 | import java.util.Collection;
6 | import java.util.HashMap;
7 | import java.util.LinkedList;
8 | import java.util.Map;
9 | import java.util.Queue;
10 | import java.util.concurrent.ConcurrentLinkedQueue;
11 |
12 | import org.junit.Test;
13 |
14 | class CollectionsSerializableBean implements Serializable {
15 | // Collections
16 | public Collection arrayList;
17 | public Collection linkedList;
18 | public Map hashMap;
19 | public Queue queue;
20 |
21 | public CollectionsSerializableBean()
22 | {
23 | super();
24 |
25 | arrayList = new ArrayList();
26 | arrayList.add("e1");
27 | arrayList.add("e2");
28 |
29 | linkedList = new LinkedList();
30 | linkedList.add("ll1");
31 | linkedList.add("ll2");
32 |
33 | hashMap = new HashMap();
34 | hashMap.put("k1", null);
35 | hashMap.put("k2", "value2");
36 | hashMap.put("k3", arrayList);
37 | hashMap.put("k3", linkedList);
38 |
39 | queue = new ConcurrentLinkedQueue();
40 | queue.add("q1");
41 | queue.add("q2");
42 | queue.add("q3");
43 | }
44 | }
45 |
46 | public class CollectionsTest {
47 |
48 | ObjectOutputStream oos;
49 | FileOutputStream fos;
50 |
51 | @Test
52 | public void testCollections() throws Exception {
53 | oos = new ObjectOutputStream(fos = new FileOutputStream("objCollections.ser"));
54 | oos.writeObject(new CollectionsSerializableBean());
55 | oos.flush();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/java/src/test/java/JFrameTest.java:
--------------------------------------------------------------------------------
1 | import java.awt.BorderLayout;
2 | import java.awt.Component;
3 | import java.awt.GridLayout;
4 | import java.awt.Rectangle;
5 | import java.awt.event.ActionEvent;
6 | import java.awt.event.ActionListener;
7 | import java.awt.event.MouseAdapter;
8 | import java.awt.event.MouseEvent;
9 | import java.awt.event.WindowAdapter;
10 | import java.awt.event.WindowEvent;
11 | import java.io.Serializable;
12 |
13 | import javax.swing.JButton;
14 | import javax.swing.JCheckBox;
15 | import javax.swing.JFrame;
16 | import javax.swing.JList;
17 | import javax.swing.JPanel;
18 | import javax.swing.JScrollPane;
19 | import javax.swing.JTextArea;
20 | import javax.swing.ListCellRenderer;
21 | import javax.swing.ListModel;
22 | import javax.swing.ListSelectionModel;
23 | import javax.swing.UIManager;
24 | import javax.swing.border.EmptyBorder;
25 |
26 | public class JFrameTest extends JFrame {
27 |
28 | public JFrameTest() {
29 | super("CheckList Example");
30 | String[] strs = { "swing", "home", "basic", "metal", "JList" };
31 |
32 | final JList list = new JList(createData(strs));
33 |
34 | list.setCellRenderer(new CheckListRenderer());
35 | list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
36 | list.setBorder(new EmptyBorder(0, 4, 0, 0));
37 | list.addMouseListener(new MouseAdapter() {
38 | public void mouseClicked(MouseEvent e) {
39 | int index = list.locationToIndex(e.getPoint());
40 | CheckableItem item = (CheckableItem) list.getModel()
41 | .getElementAt(index);
42 | item.setSelected(!item.isSelected());
43 | Rectangle rect = list.getCellBounds(index, index);
44 | list.repaint(rect);
45 | }
46 | });
47 | JScrollPane sp = new JScrollPane(list);
48 |
49 | final JTextArea textArea = new JTextArea(3, 10);
50 | JScrollPane textPanel = new JScrollPane(textArea);
51 | JButton printButton = new JButton("print");
52 | printButton.addActionListener(new ActionListener() {
53 | public void actionPerformed(ActionEvent e) {
54 | ListModel model = list.getModel();
55 | int n = model.getSize();
56 | for (int i = 0; i < n; i++) {
57 | CheckableItem item = (CheckableItem) model.getElementAt(i);
58 | if (item.isSelected()) {
59 | textArea.append(item.toString());
60 | textArea.append(System.getProperty("line.separator"));
61 | }
62 | }
63 | }
64 | });
65 | JButton clearButton = new JButton("clear");
66 | clearButton.addActionListener(new ActionListener() {
67 | public void actionPerformed(ActionEvent e) {
68 | textArea.setText("");
69 | }
70 | });
71 | JPanel panel = new JPanel(new GridLayout(2, 1));
72 | panel.add(printButton);
73 | panel.add(clearButton);
74 |
75 | getContentPane().add(sp, BorderLayout.CENTER);
76 | getContentPane().add(panel, BorderLayout.EAST);
77 | getContentPane().add(textPanel, BorderLayout.SOUTH);
78 | }
79 |
80 | private CheckableItem[] createData(String[] strs) {
81 | int n = strs.length;
82 | CheckableItem[] items = new CheckableItem[n];
83 | for (int i = 0; i < n; i++) {
84 | items[i] = new CheckableItem(strs[i]);
85 | }
86 | return items;
87 | }
88 |
89 | class CheckableItem implements Serializable {
90 | private String str;
91 |
92 | private boolean isSelected;
93 |
94 | public CheckableItem(String str) {
95 | this.str = str;
96 | isSelected = false;
97 | }
98 |
99 | public void setSelected(boolean b) {
100 | isSelected = b;
101 | }
102 |
103 | public boolean isSelected() {
104 | return isSelected;
105 | }
106 |
107 | public String toString() {
108 | return str;
109 | }
110 | }
111 |
112 | class CheckListRenderer extends JCheckBox implements ListCellRenderer {
113 |
114 | public CheckListRenderer() {
115 | setBackground(UIManager.getColor("List.textBackground"));
116 | setForeground(UIManager.getColor("List.textForeground"));
117 | }
118 |
119 | public Component getListCellRendererComponent(JList list, Object value,
120 | int index, boolean isSelected, boolean hasFocus) {
121 | setEnabled(list.isEnabled());
122 | setSelected(((CheckableItem) value).isSelected());
123 | setFont(list.getFont());
124 | setText(value.toString());
125 | return this;
126 | }
127 | }
128 |
129 | public static void main(String args[]) {
130 | try {
131 | UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
132 | } catch (Exception evt) {
133 | }
134 |
135 | JFrameTest frame = new JFrameTest();
136 | frame.addWindowListener(new WindowAdapter() {
137 | public void windowClosing(WindowEvent e) {
138 | System.exit(0);
139 | }
140 | });
141 | frame.setSize(300, 200);
142 | frame.setVisible(true);
143 | }
144 | }
--------------------------------------------------------------------------------
/tests.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import javaobj
3 | import logging
4 |
5 | class TestJavaobj(unittest.TestCase):
6 |
7 | @classmethod
8 | def setUpClass(clazz):
9 | import sys
10 | import os
11 | from subprocess import call
12 | os.chdir('./java')
13 | logging.basicConfig(level=logging.DEBUG, stream=sys.stdout)
14 | call(['mvn', 'test'])
15 | os.chdir('..')
16 |
17 | def setUp(self):
18 | pass
19 |
20 | def read_file(self, filename):
21 | file = open(filename, 'rb')
22 | return file.read()
23 |
24 | def test_0_rw(self):
25 | jobj = self.read_file("java/testChar.ser")
26 | pobj = javaobj.loads(jobj)
27 | print pobj
28 | self.assertEqual(pobj, '\x00C')
29 | jobj_ = javaobj.dumps(pobj)
30 | self.assertEqual(jobj, jobj_)
31 |
32 | def test_1(self):
33 | jobj = self.read_file("java/testDouble.ser")
34 | pobj = javaobj.loads(jobj)
35 | print pobj
36 | self.assertEqual(pobj, '\x7f\xef\xff\xff\xff\xff\xff\xff')
37 | jobj_ = javaobj.dumps(pobj)
38 | self.assertEqual(jobj, jobj_)
39 |
40 | def test_2(self):
41 | jobj = self.read_file("java/testBytes.ser")
42 | pobj = javaobj.loads(jobj)
43 | print pobj
44 | self.assertEqual(pobj, 'HelloWorld')
45 | jobj_ = javaobj.dumps(pobj)
46 | self.assertEqual(jobj, jobj_)
47 |
48 | def test_3(self):
49 | jobj = self.read_file("java/testBoolean.ser")
50 | pobj = javaobj.loads(jobj)
51 | print pobj
52 | self.assertEqual(pobj, chr(0))
53 | jobj_ = javaobj.dumps(pobj)
54 | self.assertEqual(jobj, jobj_)
55 |
56 | # def test_4(self):
57 | # jobj = self.read_file("java/testByte.ser")
58 | # pobj = javaobj.loads(jobj)
59 | # print pobj
60 | # self.assertEqual(pobj, 127)
61 | #
62 | # jobj_ = javaobj.dumps(pobj)
63 | # self.assertEqual(jobj, jobj_)
64 |
65 | def test_5(self):
66 | jobj = self.read_file("java/test_readFields.ser")
67 | pobj = javaobj.loads(jobj)
68 | print pobj
69 |
70 | self.assertEqual(pobj.aField1, 'Gabba')
71 | self.assertEqual(pobj.aField2, None)
72 |
73 | classdesc = pobj.get_class()
74 | self.assertTrue(classdesc)
75 | self.assertEqual(classdesc.serialVersionUID, 0x7F0941F5)
76 | self.assertEqual(classdesc.name, "OneTest$SerializableTestHelper")
77 | print classdesc
78 | print classdesc.flags
79 | print classdesc.fields_names
80 | print classdesc.fields_types
81 | self.assertEqual(len(classdesc.fields_names), 3)
82 |
83 | # jobj_ = javaobj.dumps(pobj)
84 | # self.assertEqual(jobj, jobj_)
85 |
86 | def test_6(self):
87 | jobj = self.read_file("java/testClass.ser")
88 | pobj = javaobj.loads(jobj)
89 | print pobj
90 | self.assertEqual(pobj.name, 'java.lang.String')
91 |
92 | # jobj_ = javaobj.dumps(pobj)
93 | # self.assertEqual(jobj, jobj_)
94 |
95 | # def test_7(self):
96 | # jobj = self.read_file("java/testSwingObject.ser")
97 | # pobj = javaobj.loads(jobj)
98 | # print pobj
99 | #
100 | # classdesc = pobj.get_class()
101 | # print classdesc
102 | # print classdesc.fields_names
103 | # print classdesc.fields_types
104 |
105 | # def test_super(self):
106 | # jobj = self.read_file("objSuper.ser")
107 | # pobj = javaobj.loads(jobj)
108 | # print pobj
109 | #
110 | # classdesc = pobj.get_class()
111 | # print classdesc
112 | # print classdesc.fields_names
113 | # print classdesc.fields_types
114 | #
115 | # print pobj.childString
116 | # print pobj.bool
117 | # print pobj.integer
118 | #
119 | # def test_arrays(self):
120 | # jobj = self.read_file("objArrays.ser")
121 | # pobj = javaobj.loads(jobj)
122 | # print pobj
123 | #
124 | # classdesc = pobj.get_class()
125 | # print classdesc
126 | # print classdesc.fields_names
127 | # print classdesc.fields_types
128 | #
129 | ## public String[] stringArr = {"1", "2", "3"};
130 | ## public int[] integerArr = {1,2,3};
131 | ## public boolean[] boolArr = {true, false, true};
132 | ## public TestConcrete[] concreteArr = {new TestConcrete(), new TestConcrete()};
133 | #
134 | # print pobj.stringArr
135 | # print pobj.integerArr
136 | # print pobj.boolArr
137 | # print pobj.concreteArr
138 | #
139 | # def test_enums(self):
140 | # jobj = self.read_file("objEnums.ser")
141 | # pobj = javaobj.loads(jobj)
142 | # print pobj
143 | #
144 | # classdesc = pobj.get_class()
145 | # print classdesc
146 | # print classdesc.fields_names
147 | # print classdesc.fields_types
148 | #
149 | # def test_exception(self):
150 | # jobj = self.read_file("objException.ser")
151 | # pobj = javaobj.loads(jobj)
152 | # print pobj
153 | #
154 | # classdesc = pobj.get_class()
155 | # print classdesc
156 | # print classdesc.fields_names
157 | # print classdesc.fields_types
158 | #
159 | # def test_sun_example(self):
160 | # marshaller = javaobj.JavaObjectUnmarshaller(open("sunExample.ser"))
161 | # pobj = marshaller.readObject()
162 | #
163 | # self.assertEqual(pobj.value, 17)
164 | # self.assertTrue(pobj.next)
165 | #
166 | # pobj = marshaller.readObject()
167 | #
168 | # self.assertEqual(pobj.value, 19)
169 | # self.assertFalse(pobj.next)
170 | #
171 | def test_collections(self):
172 | jobj = self.read_file("objCollections.ser")
173 | pobj = javaobj.loads(jobj)
174 | print pobj
175 | #
176 | # print "arrayList:", pobj.arrayList
177 | # self.assertTrue(isinstance(pobj.arrayList, list))
178 | # print "hashMap:", pobj.hashMap
179 | # self.assertTrue(isinstance(pobj.hashMap, dict))
180 | # print "linkedList:", pobj.linkedList
181 | # self.assertTrue(isinstance(pobj.linkedList, list)) # Fails
182 |
183 | if __name__ == '__main__':
184 | unittest.main()
185 |
--------------------------------------------------------------------------------
/java/src/test/java/OneTest.java:
--------------------------------------------------------------------------------
1 | import java.awt.event.WindowAdapter;
2 | import java.awt.event.WindowEvent;
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.IOException;
6 | import java.io.ObjectInputStream;
7 | import java.io.ObjectOutputStream;
8 | import java.io.Serializable;
9 | import java.util.Hashtable;
10 | import java.util.Vector;
11 |
12 | import org.junit.Before;
13 | import org.junit.Rule;
14 | import org.junit.Test;
15 | import org.junit.rules.TestName;
16 |
17 | import javax.swing.*;
18 |
19 | class MyExceptionWhenDumping implements java.io.Serializable {
20 | private static class MyException extends java.io.IOException {
21 | };
22 |
23 | public boolean anInstanceVar = false;
24 |
25 | public MyExceptionWhenDumping() {
26 | super();
27 | }
28 |
29 | private void readObject(java.io.ObjectInputStream in)
30 | throws java.io.IOException, ClassNotFoundException {
31 | in.defaultReadObject();
32 | }
33 |
34 | private void writeObject(java.io.ObjectOutputStream out)
35 | throws java.io.IOException, ClassNotFoundException {
36 | throw new MyException();
37 | }
38 | }
39 |
40 | enum Color
41 | {
42 | RED("RED"), GREEN("GREEN"), BLUE("BLUE"), UNKNOWN("UNKNOWN");
43 | private final String value;
44 |
45 | Color(String value)
46 | {
47 | this.value = value;
48 | }
49 |
50 | public String getValue()
51 | {
52 | return value;
53 | }
54 | }
55 |
56 | class ClassWithEnum implements Serializable {
57 | public Color color = Color.GREEN;
58 | public Color[] colors = {Color.GREEN, Color.BLUE, Color.RED};
59 | }
60 |
61 | class SuperAaaa implements Serializable {
62 |
63 | public String superString = "Super!!";
64 | public int integer = -1;
65 | public boolean bool = true;
66 |
67 | }
68 |
69 | class TestConcrete extends SuperAaaa implements Serializable {
70 |
71 | public String childString = "Child!!";
72 |
73 | TestConcrete() {
74 | super();
75 | }
76 |
77 | }
78 |
79 | public class OneTest {
80 |
81 | @Rule
82 | public TestName name = new TestName();
83 |
84 | ObjectOutputStream oos;
85 | ByteArrayOutputStream bao;
86 | FileOutputStream fos;
87 |
88 | public class SerializableTestHelper implements Serializable {
89 |
90 | public String aField1;
91 |
92 | public String aField2;
93 |
94 | SerializableTestHelper() {
95 | aField1 = null;
96 | aField2 = null;
97 | }
98 |
99 | SerializableTestHelper(String s, String t) {
100 | aField1 = s;
101 | aField2 = t;
102 | }
103 |
104 | private void readObject(ObjectInputStream ois) throws Exception {
105 | // note aField2 is not read
106 | ObjectInputStream.GetField fields = ois.readFields();
107 | aField1 = (String) fields.get("aField1", "Zap");
108 | }
109 |
110 | private void writeObject(ObjectOutputStream oos) throws IOException {
111 | // note aField2 is not written
112 | ObjectOutputStream.PutField fields = oos.putFields();
113 | fields.put("aField1", aField1);
114 | oos.writeFields();
115 | }
116 |
117 | public String getText1() {
118 | return aField1;
119 | }
120 |
121 | public void setText1(String s) {
122 | aField1 = s;
123 | }
124 |
125 | public String getText2() {
126 | return aField2;
127 | }
128 |
129 | public void setText2(String s) {
130 | aField2 = s;
131 | }
132 | }
133 |
134 | public static class A1 implements Serializable {
135 | private static final long serialVersionUID = 5942584913446079661L;
136 | B1 b1 = new B1();
137 | B1 b2 = b1;
138 | Vector v = new Vector();
139 | }
140 |
141 | public static class B1 implements Serializable {
142 | int i = 5;
143 | Hashtable h = new Hashtable();
144 | }
145 |
146 | @Before
147 | public void setUp() throws Exception {
148 | oos = new ObjectOutputStream(fos = new FileOutputStream(name.getMethodName() + ".ser"));
149 | }
150 |
151 | @Test
152 | public void testDouble() throws IOException {
153 | oos.writeDouble(Double.MAX_VALUE);
154 | oos.close();
155 | }
156 |
157 | @Test
158 | public void testBytes() throws IOException {
159 | oos.writeBytes("HelloWorld");
160 | oos.close();
161 | }
162 |
163 | @Test
164 | public void testBoolean() throws IOException {
165 | oos.writeBoolean(false);
166 | oos.close();
167 | }
168 |
169 | @Test
170 | public void testByte() throws IOException {
171 | oos.writeByte(127);
172 | oos.close();
173 | }
174 |
175 | @Test
176 | public void testChar() throws IOException {
177 | oos.writeChar('C');
178 | oos.close();
179 | }
180 |
181 | @Test
182 | public void test_readFields() throws Exception {
183 | oos.writeObject(new SerializableTestHelper("Gabba", "Jabba"));
184 | oos.flush();
185 | }
186 |
187 | @Test
188 | public void testClass() throws Exception {
189 | oos.writeObject(String.class);
190 | oos.flush();
191 | }
192 |
193 | @Test
194 | public void testSwingObject() throws Exception {
195 | JFrameTest frame = new JFrameTest();
196 | frame.addWindowListener(new WindowAdapter() {
197 | public void windowClosing(WindowEvent e) {
198 | System.exit(0);
199 | }
200 | });
201 | frame.setSize(300, 200);
202 | frame.setVisible(true);
203 | oos.writeObject(((JScrollPane)frame.getRootPane().getContentPane().getComponent(0)).getComponent(1));
204 | oos.flush();
205 | }
206 |
207 | @Test
208 | public void testSuper() throws Exception {
209 | oos = new ObjectOutputStream(fos = new FileOutputStream("objSuper.ser"));
210 | TestConcrete ts = new TestConcrete();
211 |
212 | // ts.setChild("and Child!!!!");
213 | oos.writeObject(ts);
214 | oos.flush();
215 | }
216 |
217 | @Test
218 | public void testEnums() throws Exception {
219 | oos = new ObjectOutputStream(fos = new FileOutputStream("objEnums.ser"));
220 | ClassWithEnum ts = new ClassWithEnum();
221 |
222 | oos.writeObject(ts);
223 | oos.flush();
224 | }
225 |
226 | @Test
227 | public void testException() throws Exception {
228 | oos = new ObjectOutputStream(fos = new FileOutputStream("objException.ser"));
229 | MyExceptionWhenDumping ts = new MyExceptionWhenDumping();
230 |
231 | oos.writeObject(ts);
232 | oos.flush();
233 | }
234 |
235 | // public void test_readObject() throws Exception {
236 | // String s = "HelloWorld";
237 | // oos.writeObject(s);
238 | // oos.close();
239 | // ois = new ObjectInputStream(new ByteArrayInputStream(bao.toByteArray()));
240 | // assertEquals("Read incorrect Object value", s, ois.readObject());
241 | // ois.close();
242 | //
243 | // // Regression for HARMONY-91
244 | // // dynamically create serialization byte array for the next hierarchy:
245 | // // - class A implements Serializable
246 | // // - class C extends A
247 | //
248 | // byte[] cName = C.class.getName().getBytes("UTF-8");
249 | // byte[] aName = A.class.getName().getBytes("UTF-8");
250 | //
251 | // ByteArrayOutputStream out = new ByteArrayOutputStream();
252 | //
253 | // byte[] begStream = new byte[] { (byte) 0xac, (byte) 0xed, // STREAM_MAGIC
254 | // (byte) 0x00, (byte) 0x05, // STREAM_VERSION
255 | // (byte) 0x73, // TC_OBJECT
256 | // (byte) 0x72, // TC_CLASSDESC
257 | // (byte) 0x00, // only first byte for C class name length
258 | // };
259 | //
260 | // out.write(begStream, 0, begStream.length);
261 | // out.write(cName.length); // second byte for C class name length
262 | // out.write(cName, 0, cName.length); // C class name
263 | //
264 | // byte[] midStream = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00,
265 | // (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
266 | // (byte) 0x21, // serialVersionUID = 33L
267 | // (byte) 0x02, // flags
268 | // (byte) 0x00, (byte) 0x00, // fields : none
269 | // (byte) 0x78, // TC_ENDBLOCKDATA
270 | // (byte) 0x72, // Super class for C: TC_CLASSDESC for A class
271 | // (byte) 0x00, // only first byte for A class name length
272 | // };
273 | //
274 | // out.write(midStream, 0, midStream.length);
275 | // out.write(aName.length); // second byte for A class name length
276 | // out.write(aName, 0, aName.length); // A class name
277 | //
278 | // byte[] endStream = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00,
279 | // (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
280 | // (byte) 0x0b, // serialVersionUID = 11L
281 | // (byte) 0x02, // flags
282 | // (byte) 0x00, (byte) 0x01, // fields
283 | //
284 | // (byte) 0x4c, // field description: type L (object)
285 | // (byte) 0x00, (byte) 0x04, // length
286 | // // field = 'name'
287 | // (byte) 0x6e, (byte) 0x61, (byte) 0x6d, (byte) 0x65,
288 | //
289 | // (byte) 0x74, // className1: TC_STRING
290 | // (byte) 0x00, (byte) 0x12, // length
291 | // //
292 | // (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
293 | // (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61,
294 | // (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53,
295 | // (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e,
296 | // (byte) 0x67, (byte) 0x3b,
297 | //
298 | // (byte) 0x78, // TC_ENDBLOCKDATA
299 | // (byte) 0x70, // NULL super class for A class
300 | //
301 | // // classdata
302 | // (byte) 0x74, // TC_STRING
303 | // (byte) 0x00, (byte) 0x04, // length
304 | // (byte) 0x6e, (byte) 0x61, (byte) 0x6d, (byte) 0x65, // value
305 | // };
306 | //
307 | // out.write(endStream, 0, endStream.length);
308 | // out.flush();
309 | //
310 | // // read created serial. form
311 | // ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
312 | // out.toByteArray()));
313 | // Object o = ois.readObject();
314 | // assertEquals(C.class, o.getClass());
315 | //
316 | // // Regression for HARMONY-846
317 | // assertNull(new ObjectInputStream() {}.readObject());
318 | // }
319 |
320 |
321 | }
322 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/javaobj.py:
--------------------------------------------------------------------------------
1 | # Licensed under the Apache License, Version 2.0 (the "License");
2 | # you may not use this file except in compliance with the License.
3 | # You may obtain a copy of the License at
4 | #
5 | # http://www.apache.org/licenses/LICENSE-2.0
6 | #
7 | # Unless required by applicable law or agreed to in writing, software
8 | # distributed under the License is distributed on an "AS IS" BASIS,
9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | # See the License for the specific language governing permissions and
11 | # limitations under the License.
12 |
13 | """
14 | Provides functions for reading (writing is WIP currently) of Java
15 | objects serialized by ObjectOutputStream. This form of object
16 | representation is a standard data interchange format in Java world.
17 |
18 | javaobj module exposes an API familiar to users of the standard modules
19 | such as marshal, pickle and json.
20 |
21 | See: http://download.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html
22 | """
23 |
24 | import StringIO
25 | import struct
26 |
27 | try:
28 | import logging
29 | except ImportError:
30 | def log_debug(message, ident=0):
31 | pass
32 | def log_error(message, ident=0):
33 | pass
34 | else:
35 | _log = logging.getLogger(__name__)
36 | def log_debug(message, ident=0):
37 | _log.debug(" " * (ident * 2) + str(message))
38 | def log_error(message, ident=0):
39 | _log.error(" " * (ident * 2) + str(message))
40 |
41 | __version__ = "$Revision: 20 $"
42 |
43 |
44 | def load(file_object, *args):
45 | """
46 | Deserializes Java primitive data and objects serialized by ObjectOutputStream
47 | from a file-like object.
48 | """
49 | marshaller = JavaObjectUnmarshaller(file_object)
50 | for t in args:
51 | marshaller.add_transformer(t)
52 | marshaller.add_transformer(DefaultObjectTransformer())
53 | return marshaller.readObject()
54 |
55 |
56 | def load_all(file_object):
57 | marshaller = JavaObjectUnmarshaller(file_object)
58 | marshaller.add_transformer(DefaultObjectTransformer())
59 |
60 | res = []
61 | while marshaller.data_left:
62 | res.append(marshaller.readObject())
63 | return res
64 |
65 |
66 | def loads(string, *args):
67 | """
68 | Deserializes Java objects and primitive data serialized by ObjectOutputStream
69 | from a string.
70 | """
71 | f = StringIO.StringIO(string)
72 | marshaller = JavaObjectUnmarshaller(f)
73 | for t in args:
74 | marshaller.add_transformer(t)
75 | marshaller.add_transformer(DefaultObjectTransformer())
76 | return marshaller.readObject()
77 |
78 |
79 | def dumps(object, *args):
80 | """
81 | Serializes Java primitive data and objects unmarshaled by load(s) before into string.
82 | """
83 | marshaller = JavaObjectMarshaller()
84 | for t in args:
85 | marshaller.add_transformer(t)
86 | return marshaller.dump(object)
87 |
88 |
89 | class JavaClass(object):
90 | def __init__(self):
91 | self.name = None
92 | self.serialVersionUID = None
93 | self.flags = None
94 | self.handle = None
95 | self.fields_names = []
96 | self.fields_types = []
97 | self.superclass = None
98 |
99 | def __str__(self):
100 | return self.__repr__()
101 |
102 | def __repr__(self):
103 | return "[%s:0x%X]" % (self.name, self.serialVersionUID)
104 |
105 | def __eq__(self, other):
106 | if not isinstance(other, type(self)):
107 | return False
108 | return (self.name == other.name and
109 | self.serialVersionUID == other.serialVersionUID and
110 | self.flags == other.flags and
111 | self.fields_names == other.fields_names and
112 | self.fields_types == other.fields_types and
113 | self.superclass == other.superclass)
114 |
115 |
116 | class JavaObject(object):
117 |
118 | def __init__(self):
119 | self.classdesc = None
120 | self.annotations = []
121 |
122 | def get_class(self):
123 | return self.classdesc
124 |
125 | def __str__(self):
126 | return self.__repr__()
127 |
128 | def __repr__(self):
129 | name = "UNKNOWN"
130 | if self.classdesc:
131 | name = self.classdesc.name
132 | return "" % name
133 |
134 | def __eq__(self, other):
135 | if not isinstance(other, type(self)):
136 | return False
137 | res = (self.classdesc == other.classdesc and
138 | self.annotations == other.annotations)
139 | for name in self.classdesc.fields_names:
140 | res = (res and
141 | getattr(self, name) == getattr(other, name))
142 | return res
143 |
144 | def copy(self, new_object):
145 | new_object.classdesc = self.classdesc
146 | new_object.annotations = self.annotations
147 |
148 | for name in self.classdesc.fields_names:
149 | new_object.__setattr__(name, getattr(self, name))
150 |
151 |
152 | class JavaString(str):
153 | def __init__(self, *args, **kwargs):
154 | str.__init__(self, *args, **kwargs)
155 |
156 | def __eq__(self, other):
157 | if not isinstance(other, str):
158 | return False
159 | return str.__eq__(self, other)
160 |
161 |
162 | class JavaEnum(JavaObject):
163 | def __init__(self, constant=None):
164 | super(JavaEnum, self).__init__()
165 | self.constant = constant
166 |
167 |
168 | class JavaArray(list, JavaObject):
169 | def __init__(self, classdesc=None):
170 | list.__init__(self)
171 | JavaObject.__init__(self)
172 | self.classdesc = classdesc
173 |
174 |
175 | class JavaObjectConstants:
176 |
177 | STREAM_MAGIC = 0xaced
178 | STREAM_VERSION = 0x05
179 |
180 | TC_NULL = 0x70
181 | TC_REFERENCE = 0x71
182 | TC_CLASSDESC = 0x72
183 | TC_OBJECT = 0x73
184 | TC_STRING = 0x74
185 | TC_ARRAY = 0x75
186 | TC_CLASS = 0x76
187 | TC_BLOCKDATA = 0x77
188 | TC_ENDBLOCKDATA = 0x78
189 | TC_RESET = 0x79
190 | TC_BLOCKDATALONG = 0x7A
191 | TC_EXCEPTION = 0x7B
192 | TC_LONGSTRING = 0x7C
193 | TC_PROXYCLASSDESC = 0x7D
194 | TC_ENUM = 0x7E
195 | TC_MAX = 0x7E
196 |
197 | # classDescFlags
198 | SC_WRITE_METHOD = 0x01 # if SC_SERIALIZABLE
199 | SC_BLOCK_DATA = 0x08 # if SC_EXTERNALIZABLE
200 | SC_SERIALIZABLE = 0x02
201 | SC_EXTERNALIZABLE = 0x04
202 | SC_ENUM = 0x10
203 |
204 | # type definition chars (typecode)
205 | TYPE_BYTE = 'B' # 0x42
206 | TYPE_CHAR = 'C'
207 | TYPE_DOUBLE = 'D' # 0x44
208 | TYPE_FLOAT = 'F' # 0x46
209 | TYPE_INTEGER = 'I' # 0x49
210 | TYPE_LONG = 'J' # 0x4A
211 | TYPE_SHORT = 'S' # 0x53
212 | TYPE_BOOLEAN = 'Z' # 0x5A
213 | TYPE_OBJECT = 'L' # 0x4C
214 | TYPE_ARRAY = '[' # 0x5B
215 |
216 | # list of supported typecodes listed above
217 | TYPECODES_LIST = [
218 | # primitive types
219 | TYPE_BYTE,
220 | TYPE_CHAR,
221 | TYPE_DOUBLE,
222 | TYPE_FLOAT,
223 | TYPE_INTEGER,
224 | TYPE_LONG,
225 | TYPE_SHORT,
226 | TYPE_BOOLEAN,
227 | # object types
228 | TYPE_OBJECT,
229 | TYPE_ARRAY ]
230 |
231 | BASE_REFERENCE_IDX = 0x7E0000
232 |
233 |
234 | class JavaObjectUnmarshaller(JavaObjectConstants):
235 |
236 | def __init__(self, stream=None):
237 | self.opmap = {
238 | self.TC_NULL: self.do_null,
239 | self.TC_CLASSDESC: self.do_classdesc,
240 | self.TC_OBJECT: self.do_object,
241 | self.TC_STRING: self.do_string,
242 | self.TC_LONGSTRING: self.do_string_long,
243 | self.TC_ARRAY: self.do_array,
244 | self.TC_CLASS: self.do_class,
245 | self.TC_BLOCKDATA: self.do_blockdata,
246 | self.TC_BLOCKDATALONG: self.do_blockdata_long,
247 | self.TC_REFERENCE: self.do_reference,
248 | self.TC_ENUM: self.do_enum,
249 | self.TC_ENDBLOCKDATA: self.do_null, # note that we are reusing of do_null
250 | }
251 | self.current_object = None
252 | self.reference_counter = 0
253 | self.references = []
254 | self.object_stream = stream
255 | self._readStreamHeader()
256 | self.object_transformers = []
257 | self.data_left = True
258 |
259 | def readObject(self):
260 | try:
261 | opcode, res = self._read_and_exec_opcode(ident=0) # TODO: add expects
262 |
263 | position_bak = self.object_stream.tell()
264 | the_rest = self.object_stream.read()
265 | if len(the_rest):
266 | log_error("Warning!!!!: Stream still has %s bytes left. Enable debug mode of logging to see the hexdump." % len(the_rest))
267 | log_debug(self._create_hexdump(the_rest, position_bak))
268 | self.data_left = True
269 | else:
270 | log_debug("Java Object unmarshalled succesfully!")
271 | self.data_left = False
272 | self.object_stream.seek(position_bak)
273 |
274 | return res
275 | except Exception as e:
276 | self._oops_dump_state()
277 | raise
278 |
279 | def add_transformer(self, transformer):
280 | self.object_transformers.append(transformer)
281 |
282 | def _readStreamHeader(self):
283 | (magic, version) = self._readStruct(">HH")
284 | if magic != self.STREAM_MAGIC or version != self.STREAM_VERSION:
285 | raise IOError("The stream is not java serialized object. Invalid stream header: %04X%04X" % (magic, version))
286 |
287 | def _read_and_exec_opcode(self, ident=0, expect=None):
288 | position = self.object_stream.tell()
289 | (opid, ) = self._readStruct(">B")
290 | log_debug("OpCode: 0x%X (at offset: 0x%X)" % (opid, position), ident)
291 | if expect and opid not in expect:
292 | raise IOError("Unexpected opcode 0x%X" % opid)
293 | handler = self.opmap.get(opid)
294 | if not handler:
295 | raise RuntimeError("Unknown OpCode in the stream: 0x%x" % opid)
296 | return (opid, handler(ident=ident))
297 |
298 | def _readStruct(self, unpack):
299 | length = struct.calcsize(unpack)
300 | ba = self.object_stream.read(length)
301 | if len(ba) != length:
302 | raise RuntimeError("Stream has been ended unexpectedly while unmarshaling. (%d vs %d)" % (len(ba), length))
303 | return struct.unpack(unpack, ba)
304 |
305 | def _readString(self, mod="H"):
306 | (length, ) = self._readStruct(">" + mod)
307 | ba = self.object_stream.read(length)
308 | return ba
309 |
310 | def do_classdesc(self, parent=None, ident=0):
311 | # TC_CLASSDESC className serialVersionUID newHandle classDescInfo
312 | # classDescInfo:
313 | # classDescFlags fields classAnnotation superClassDesc
314 | # classDescFlags:
315 | # (byte) // Defined in Terminal Symbols and Constants
316 | # fields:
317 | # (short) fieldDesc[count]
318 |
319 | # fieldDesc:
320 | # primitiveDesc
321 | # objectDesc
322 | # primitiveDesc:
323 | # prim_typecode fieldName
324 | # objectDesc:
325 | # obj_typecode fieldName className1
326 | clazz = JavaClass()
327 | log_debug("[classdesc]", ident)
328 | ba = self._readString()
329 | clazz.name = ba
330 | log_debug("Class name: %s" % ba, ident)
331 | (serialVersionUID, newHandle, classDescFlags) = self._readStruct(">LLB")
332 | clazz.serialVersionUID = serialVersionUID
333 | clazz.flags = classDescFlags
334 | clazz.handle = newHandle
335 |
336 | self._add_reference(clazz, ident)
337 |
338 | log_debug("Serial: 0x%X newHandle: 0x%X. classDescFlags: 0x%X" % (serialVersionUID, newHandle, classDescFlags), ident)
339 | (length, ) = self._readStruct(">H")
340 | log_debug("Fields num: 0x%X" % length, ident)
341 |
342 | clazz.fields_names = []
343 | clazz.fields_types = []
344 | for fieldId in range(length):
345 | (typecode, ) = self._readStruct(">B")
346 | field_name = self._readString()
347 | field_type = None
348 | field_type = self._convert_char_to_type(typecode)
349 |
350 | if field_type == self.TYPE_ARRAY:
351 | opcode, field_type = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
352 | assert type(field_type) is JavaString
353 | # if field_type is not None:
354 | # field_type = "array of " + field_type
355 | # else:
356 | # field_type = "array of None"
357 | elif field_type == self.TYPE_OBJECT:
358 | opcode, field_type = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
359 | assert type(field_type) is JavaString
360 |
361 | log_debug("FieldName: 0x%X" % typecode + " " + str(field_name) + " " + str(field_type), ident)
362 | assert field_name is not None
363 | assert field_type is not None
364 |
365 | clazz.fields_names.append(field_name)
366 | clazz.fields_types.append(field_type)
367 | if parent:
368 | parent.__fields = clazz.fields_names
369 | parent.__types = clazz.fields_types
370 | # classAnnotation
371 | (opid, ) = self._readStruct(">B")
372 | log_debug("OpCode: 0x%X" % opid, ident)
373 | if opid != self.TC_ENDBLOCKDATA:
374 | raise NotImplementedError("classAnnotation isn't implemented yet")
375 | # superClassDesc
376 | opcode, superclassdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_NULL, self.TC_REFERENCE])
377 | log_debug(str(superclassdesc), ident)
378 | clazz.superclass = superclassdesc
379 |
380 | return clazz
381 |
382 | def do_blockdata(self, parent=None, ident=0):
383 | # TC_BLOCKDATA (unsigned byte) (byte)[size]
384 | log_debug("[blockdata]", ident)
385 | (length, ) = self._readStruct(">B")
386 | ba = self.object_stream.read(length)
387 | return ba
388 |
389 | def do_blockdata_long(self, parent=None, ident=0):
390 | # TC_BLOCKDATALONG (int) (byte)[size]
391 | log_debug("[blockdata]", ident)
392 | (length, ) = self._readStruct(">I")
393 | ba = self.object_stream.read(length)
394 | return ba
395 |
396 | def do_class(self, parent=None, ident=0):
397 | # TC_CLASS classDesc newHandle
398 | log_debug("[class]", ident)
399 |
400 | # TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
401 | opcode, classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
402 | log_debug("Classdesc: %s" % classdesc, ident)
403 | self._add_reference(classdesc, ident)
404 | return classdesc
405 |
406 | def do_object(self, parent=None, ident=0):
407 | # TC_OBJECT classDesc newHandle classdata[] // data for each class
408 | java_object = JavaObject()
409 | log_debug("[object]", ident)
410 | log_debug("java_object.annotations just after instantination: " + str(java_object.annotations), ident)
411 |
412 | # TODO: what to do with "(ClassDesc)prevObject". (see 3rd line for classDesc:)
413 | opcode, classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
414 | # self.TC_REFERENCE hasn't shown in spec, but actually is here
415 |
416 | self._add_reference(java_object, ident)
417 |
418 | # classdata[]
419 |
420 | # Store classdesc of this object
421 | java_object.classdesc = classdesc
422 |
423 | if classdesc.flags & self.SC_EXTERNALIZABLE and not classdesc.flags & self.SC_BLOCK_DATA:
424 | raise NotImplementedError("externalContents isn't implemented yet") # TODO:
425 |
426 | if classdesc.flags & self.SC_SERIALIZABLE:
427 | # create megalist
428 | tempclass = classdesc
429 | megalist = []
430 | megatypes = []
431 | while tempclass:
432 | log_debug(">>> " + str(tempclass.fields_names) + " " + str(tempclass), ident)
433 | log_debug(">>> " + str(tempclass.fields_types), ident)
434 | fieldscopy = tempclass.fields_names[:]
435 | fieldscopy.extend(megalist)
436 | megalist = fieldscopy
437 |
438 | fieldscopy = tempclass.fields_types[:]
439 | fieldscopy.extend(megatypes)
440 | megatypes = fieldscopy
441 |
442 | tempclass = tempclass.superclass
443 |
444 | log_debug("Values count: %s" % str(len(megalist)), ident)
445 | log_debug("Prepared list of values: %s" % str(megalist), ident)
446 | log_debug("Prepared list of types: %s" % str(megatypes), ident)
447 |
448 | for field_name, field_type in zip(megalist, megatypes):
449 | res = self._read_value(field_type, ident, name=field_name)
450 | java_object.__setattr__(field_name, res)
451 |
452 | if classdesc.flags & self.SC_SERIALIZABLE and classdesc.flags & self.SC_WRITE_METHOD or classdesc.flags & self.SC_EXTERNALIZABLE and classdesc.flags & self.SC_BLOCK_DATA:
453 | # objectAnnotation
454 | log_debug("java_object.annotations before: " + str(java_object.annotations), ident)
455 | while opcode != self.TC_ENDBLOCKDATA:
456 | opcode, obj = self._read_and_exec_opcode(ident=ident+1) # , expect=[self.TC_ENDBLOCKDATA, self.TC_BLOCKDATA, self.TC_OBJECT, self.TC_NULL, self.TC_REFERENCE])
457 | if opcode != self.TC_ENDBLOCKDATA:
458 | java_object.annotations.append(obj)
459 | log_debug("objectAnnotation value: " + str(obj), ident)
460 | log_debug("java_object.annotations after: " + str(java_object.annotations), ident)
461 |
462 | # Transform object
463 | for transformer in self.object_transformers:
464 | tmp_object = transformer.transform(java_object)
465 | if tmp_object is not java_object:
466 | java_object = tmp_object
467 | break
468 |
469 | log_debug(">>> java_object: " + str(java_object), ident)
470 | return java_object
471 |
472 | def do_string(self, parent=None, ident=0):
473 | log_debug("[string]", ident)
474 | ba = JavaString(self._readString())
475 | self._add_reference(ba, ident)
476 | return ba
477 |
478 | def do_string_long(self, parent=None, ident=0):
479 | log_debug("[long string]", ident)
480 | ba = JavaString(self._readString("Q"))
481 | self._add_reference(ba, ident)
482 | return ba
483 |
484 | def do_array(self, parent=None, ident=0):
485 | # TC_ARRAY classDesc newHandle (int) values[size]
486 | log_debug("[array]", ident)
487 | opcode, classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
488 |
489 | array = JavaArray(classdesc)
490 |
491 | self._add_reference(array, ident)
492 |
493 | (size, ) = self._readStruct(">i")
494 | log_debug("size: " + str(size), ident)
495 |
496 | type_char = classdesc.name[0]
497 | assert type_char == self.TYPE_ARRAY
498 | type_char = classdesc.name[1]
499 |
500 | if type_char == self.TYPE_OBJECT or type_char == self.TYPE_ARRAY:
501 | for i in range(size):
502 | opcode, res = self._read_and_exec_opcode(ident=ident+1)
503 | log_debug("Object value: %s" % str(res), ident)
504 | array.append(res)
505 | else:
506 | for i in range(size):
507 | res = self._read_value(type_char, ident)
508 | log_debug("Native value: %s" % str(res), ident)
509 | array.append(res)
510 |
511 | return array
512 |
513 | def do_reference(self, parent=None, ident=0):
514 | (handle, ) = self._readStruct(">L")
515 | log_debug("## Reference handle: 0x%x" % (handle), ident)
516 | return self.references[handle - self.BASE_REFERENCE_IDX]
517 |
518 | def do_null(self, parent=None, ident=0):
519 | return None
520 |
521 | def do_enum(self, parent=None, ident=0):
522 | # TC_ENUM classDesc newHandle enumConstantName
523 | enum = JavaEnum()
524 | opcode, classdesc = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_CLASSDESC, self.TC_PROXYCLASSDESC, self.TC_NULL, self.TC_REFERENCE])
525 | enum.classdesc = classdesc
526 | self._add_reference(enum, ident)
527 | opcode, enumConstantName = self._read_and_exec_opcode(ident=ident+1, expect=[self.TC_STRING, self.TC_REFERENCE])
528 |
529 | enum.constant = enumConstantName
530 | return enum
531 |
532 | def _create_hexdump(self, src, start_offset=0, length=16):
533 | FILTER = ''.join([(len(repr(chr(x)))==3) and chr(x) or '.' for x in range(256)])
534 | result = []
535 | for i in xrange(0, len(src), length):
536 | s = src[i:i+length]
537 | hexa = ' '.join(["%02X" % ord(x) for x in s])
538 | printable = s.translate(FILTER)
539 | result.append("%04X %-*s %s\n" % (i+start_offset, length*3, hexa, printable))
540 | return ''.join(result)
541 |
542 | def _read_value(self, field_type, ident, name = ""):
543 | if len(field_type) > 1:
544 | cls = field_type[1:]
545 | field_type = field_type[0] # We don't need details for arrays and objects
546 |
547 | if field_type == self.TYPE_BOOLEAN:
548 | (val, ) = self._readStruct(">B")
549 | res = bool(val)
550 | elif field_type == self.TYPE_BYTE:
551 | (res, ) = self._readStruct(">b")
552 | elif field_type == self.TYPE_SHORT:
553 | (res, ) = self._readStruct(">h")
554 | elif field_type == self.TYPE_INTEGER:
555 | (res, ) = self._readStruct(">i")
556 | elif field_type == self.TYPE_LONG:
557 | (res, ) = self._readStruct(">q")
558 | elif field_type == self.TYPE_FLOAT:
559 | (res, ) = self._readStruct(">f")
560 | elif field_type == self.TYPE_DOUBLE:
561 | (res, ) = self._readStruct(">d")
562 | elif field_type == self.TYPE_OBJECT or field_type == self.TYPE_ARRAY:
563 | try:
564 | opcode, res = self._read_and_exec_opcode(ident=ident+1)
565 | except RuntimeError:
566 | if cls == 'java/lang/String;':
567 | res = JavaString(self._readString())
568 | else:
569 | raise
570 | else:
571 | raise RuntimeError("Unknown typecode: %s" % field_type)
572 | log_debug("* %s %s: " % (field_type, name) + str(res), ident)
573 | return res
574 |
575 | def _convert_char_to_type(self, type_char):
576 | typecode = type_char
577 | if type(type_char) is int:
578 | typecode = chr(type_char)
579 |
580 | if typecode in self.TYPECODES_LIST:
581 | return typecode
582 | else:
583 | raise RuntimeError("Typecode %s (%s) isn't supported." % (type_char, typecode))
584 |
585 | def _add_reference(self, obj, ident=0):
586 | log_debug('## New reference handle 0x%X' % (len(self.references) + self.BASE_REFERENCE_IDX,), ident)
587 | self.references.append(obj)
588 |
589 | def _oops_dump_state(self):
590 | log_error("==Oops state dump" + "=" * (30 - 17))
591 | log_error("References: %s" % str(self.references))
592 | log_error("Stream seeking back at -16 byte (2nd line is an actual position!):")
593 | self.object_stream.seek(-16, 1)
594 | position = self.object_stream.tell()
595 | the_rest = self.object_stream.read()
596 | if len(the_rest):
597 | log_error(self._create_hexdump(the_rest, position))
598 | log_error("=" * 30)
599 |
600 |
601 | class JavaObjectMarshaller(JavaObjectConstants):
602 |
603 | def __init__(self, stream=None):
604 | self.object_stream = stream
605 | self.object_transformers = []
606 |
607 | def add_transformer(self, transformer):
608 | self.object_transformers.append(transformer)
609 |
610 | def dump(self, obj):
611 |
612 | self.object_obj = obj
613 | self.object_stream = StringIO.StringIO()
614 | self._writeStreamHeader()
615 | self.writeObject(obj)
616 | return self.object_stream.getvalue()
617 |
618 | def _writeStreamHeader(self):
619 | self._writeStruct(">HH", 4, (self.STREAM_MAGIC, self.STREAM_VERSION))
620 |
621 | def writeObject(self, obj):
622 | log_debug("Writing object of type " + str(type(obj)) + " " + str(obj))
623 | if isinstance(obj, JavaArray):
624 | self.write_array(obj)
625 | elif isinstance(obj, JavaEnum):
626 | self.write_enum(obj)
627 | elif isinstance(obj, JavaObject):
628 | self.write_object(obj)
629 | elif isinstance(obj, JavaString):
630 | self.write_string(obj)
631 | elif isinstance(obj, JavaClass):
632 | self.write_class(obj)
633 | elif obj is None:
634 | self.write_null()
635 | elif type(obj) is str:
636 | self.write_blockdata(obj)
637 | else:
638 | raise RuntimeError("Object serialization of type %s is not supported." % str(type(obj)))
639 |
640 | def _writeStruct(self, unpack, length, args):
641 | ba = struct.pack(unpack, *args)
642 | self.object_stream.write(ba)
643 |
644 | def _writeString(self, string):
645 | length = len(string)
646 | self._writeStruct(">H", 2, (length, ))
647 | self.object_stream.write(string)
648 |
649 | def write_string(self, obj):
650 | self._writeStruct(">B", 1, (self.TC_STRING,))
651 | self._writeString(obj)
652 |
653 | def write_enum(self, obj):
654 | self._writeStruct(">B", 1, (self.TC_ENUM, ))
655 | self.write_classdesc(obj.get_class())
656 |
657 | self.write_string(obj.constant)
658 |
659 | def write_blockdata(self, obj, parent=None):
660 | # TC_BLOCKDATA (unsigned byte) (byte)[size]
661 | length = len(obj)
662 | if length <= 256:
663 | self._writeStruct(">B", 1, (self.TC_BLOCKDATA, ))
664 | self._writeStruct(">B", 1, (length, ))
665 | else:
666 | self._writeStruct(">B", 1, (self.TC_BLOCKDATALONG, ))
667 | self._writeStruct(">I", 1, (length, ))
668 | self.object_stream.write(obj)
669 |
670 | def write_null(self):
671 | self._writeStruct(">B", 1, (self.TC_NULL, ))
672 |
673 | def write_object(self, obj, parent=None):
674 |
675 | # Transform object
676 | for transformer in self.object_transformers:
677 | tmp_object = transformer.transform(obj)
678 | if tmp_object is not obj:
679 | obj = tmp_object
680 | break
681 |
682 | self._writeStruct(">B", 1, (self.TC_OBJECT, ))
683 | cls = obj.get_class()
684 | self.write_classdesc(cls)
685 |
686 | all_names = []
687 | all_types = []
688 | tmpcls = cls
689 | while tmpcls:
690 | all_names += tmpcls.fields_names
691 | all_types += tmpcls.fields_types
692 | tmpcls = tmpcls.superclass
693 |
694 | del tmpcls
695 | for name, type in zip(all_names, all_types):
696 | try:
697 | self._write_value(type, getattr(obj, name))
698 | except AttributeError as e:
699 | log_error("%s e, %s %s" % (str(e), repr(obj), repr(dir(obj))))
700 | raise
701 |
702 | del all_names, all_types
703 |
704 | if (cls.flags & self.SC_SERIALIZABLE and cls.flags & self.SC_WRITE_METHOD or
705 | cls.flags & self.SC_EXTERNALIZABLE and cls.flags & self.SC_BLOCK_DATA):
706 | for annot in obj.annotations:
707 | log_debug("Write annotation %s for %s" % (repr(annot), repr(obj),))
708 | if annot == None:
709 | self.write_null()
710 | else:
711 | self.writeObject(annot)
712 | self._writeStruct('>B', 1, (self.TC_ENDBLOCKDATA,))
713 |
714 | def write_class(self, obj, parent=None):
715 | self._writeStruct(">B", 1, (self.TC_CLASS,))
716 | self.write_classdesc(obj)
717 |
718 | def write_classdesc(self, obj, parent=None):
719 | self._writeStruct(">B", 1, (self.TC_CLASSDESC, ))
720 | self._writeString(obj.name)
721 | self._writeStruct(">LLB", 1, (obj.serialVersionUID, obj.handle, obj.flags))
722 | self._writeStruct(">H", 1, (len(obj.fields_names), ))
723 |
724 | for name,type in zip(obj.fields_names, obj.fields_types):
725 | self._writeStruct(">B", 1,
726 | (self._convert_type_to_char(type),))
727 | self._writeString(name)
728 | if type[0] in (self.TYPE_OBJECT, self.TYPE_ARRAY):
729 | self.write_string(type)
730 |
731 | self._writeStruct(">B", 1, (self.TC_ENDBLOCKDATA,))
732 | if obj.superclass:
733 | self.write_classdesc(obj.superclass)
734 | else:
735 | self.write_null()
736 |
737 | def write_array(self, obj):
738 | self._writeStruct(">B", 1, (self.TC_ARRAY,))
739 | self.write_classdesc(obj.get_class())
740 | self._writeStruct(">i", 1, (len(obj),))
741 |
742 | classdesc = obj.get_class()
743 |
744 | type_char = classdesc.name[0]
745 | assert type_char == self.TYPE_ARRAY
746 | type_char = classdesc.name[1]
747 |
748 | if type_char == self.TYPE_OBJECT:
749 | for o in obj:
750 | self.write_object(o)
751 | elif type_char == self.TYPE_ARRAY:
752 | for a in obj:
753 | self.write_array(a)
754 | else:
755 | log_debug("Write array of type %s" % type_char)
756 | for v in obj:
757 | self._write_value(type_char, v)
758 |
759 | def _write_value(self, field_type, value):
760 | if len(field_type) > 1:
761 | field_type = field_type[0] # We don't need details for arrays and objects
762 |
763 | if field_type == self.TYPE_BOOLEAN:
764 | self._writeStruct(">B", 1, (1 if value else 0,))
765 | elif field_type == self.TYPE_BYTE:
766 | if value > 127:
767 | self._writeStruct(">B", 1, (value,))
768 | else:
769 | self._writeStruct(">b", 1, (value,))
770 | elif field_type == self.TYPE_SHORT:
771 | self._writeStruct(">h", 1, (value,))
772 | elif field_type == self.TYPE_INTEGER:
773 | self._writeStruct(">i", 1, (value,))
774 | elif field_type == self.TYPE_LONG:
775 | self._writeStruct(">q", 1, (value,))
776 | elif field_type == self.TYPE_FLOAT:
777 | self._writeStruct(">f", 1, (value,))
778 | elif field_type == self.TYPE_DOUBLE:
779 | self._writeStruct(">d", 1, (value,))
780 | elif field_type == self.TYPE_OBJECT or field_type == self.TYPE_ARRAY:
781 | if value == None:
782 | self.write_null()
783 | elif isinstance(value, JavaEnum):
784 | self.write_enum(value)
785 | elif isinstance(value, JavaObject):
786 | self.write_object(value)
787 | elif isinstance(value, JavaString):
788 | self.write_string(value)
789 | elif isinstance(value, str):
790 | self.write_blockdata(value)
791 | else:
792 | raise RuntimeError("Unknown typecode: %s" % field_type)
793 | else:
794 | raise RuntimeError("Unknown typecode: %s" % field_type)
795 |
796 | def _convert_type_to_char(self, type_char):
797 | typecode = type_char
798 | if type(type_char) is int:
799 | typecode = chr(type_char)
800 |
801 | if typecode in self.TYPECODES_LIST:
802 | return ord(typecode)
803 | elif len(typecode) > 1:
804 | if typecode[0] == 'L':
805 | return ord(self.TYPE_OBJECT)
806 | elif typecode[0] == '[':
807 | return ord(self.TYPE_ARRAY)
808 |
809 | raise RuntimeError("Typecode %s (%s) isn't supported." % (type_char, typecode))
810 |
811 | class DefaultObjectTransformer(object):
812 |
813 | class JavaList(list, JavaObject):
814 | def __init__(self, *args, **kwargs):
815 | list.__init__(self, *args, **kwargs)
816 | JavaObject.__init__(self)
817 |
818 | class JavaMap(dict, JavaObject):
819 | def __init__(self, *args, **kwargs):
820 | dict.__init__(self, *args, **kwargs)
821 | JavaObject.__init__(self)
822 |
823 | def transform(self, object):
824 | if object.get_class().name == "java.util.ArrayList":
825 | # * @serialData The length of the array backing the ArrayList
826 | # * instance is emitted (int), followed by all of its elements
827 | # * (each an Object) in the proper order.
828 | #print "---"
829 | #print "java.util.ArrayList"
830 | #print object.annotations
831 | #print "---"
832 | new_object = self.JavaList()
833 | object.copy(new_object)
834 | new_object.extend(object.annotations[1:])
835 | #print ">>> object:", new_object
836 | return new_object
837 | if object.get_class().name == "java.util.LinkedList":
838 | #print "---"
839 | #print
840 | #print "java.util.LinkedList"
841 | #print object.annotations
842 | #print "---"
843 | new_object = self.JavaList()
844 | object.copy(new_object)
845 | new_object.extend(object.annotations[1:])
846 | #print ">>> object:", new_object
847 | return new_object
848 | if object.get_class().name == "java.util.HashMap":
849 | #print "---"
850 | #print
851 | #print "java.util.HashMap"
852 | #print object.annotations
853 | #print "---"
854 | new_object = self.JavaMap()
855 | object.copy(new_object)
856 |
857 | for i in range(1, len(object.annotations),2):
858 | new_object[object.annotations[i]] = object.annotations[i+1]
859 |
860 | #print ">>> object:", new_object
861 | return new_object
862 |
863 | return object
864 |
--------------------------------------------------------------------------------