├── .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 | --------------------------------------------------------------------------------