Skip to content

Java serialization

Sayapin Alexander edited this page Aug 13, 2017 · 9 revisions

Ссылки по теме

Мотивация.

Целью изучения и этого раздела является создание библиотек для взаимодействия Java и PHP:

Пример приложения для кодирования

package test.serialize;

package test.serialize;

import java.io.*;
import java.util.HashMap;

class Main {
    public static class Cls1 implements Serializable {
        protected Long val = new Long(123);
    }

    public static class Cls2 extends Cls1 {
        protected String val2 = "Test string";
    }

    public static void main(String[] args) throws Exception {
        write("Boolean(true)",(oos)->oos.writeBoolean(true));
        write("Boolean(false)",(oos)->oos.writeBoolean(false));
        write("Byte(0x11)",(oos)->oos.writeByte(0x11));
        write("Bytes(ab)",(oos)->oos.writeBytes("ab"));
        write("Char(z)",(oos)->oos.writeChar('z'));
        write("Chars(abc)",(oos)->oos.writeChars("abc"));
        write("Int(1234)",(oos)->oos.writeInt(1234));
        write("Long(1234)",(oos)->oos.writeLong(1234));
        write("Short(1234)",(oos)->oos.writeShort(1234));

        write("Object(a)",(oos)->oos.writeObject("a"));
        write("Object(п)",(oos)->oos.writeObject("п"));

        write("Object(new HashMap<>())",(oos)->oos.writeObject(new HashMap<>()));

        write("Object(new Cls1)",(oos)->oos.writeObject(new Cls1()));

        write("Object(new Cls2)",(oos)->oos.writeObject(new Cls2()));
    }

    public static void write(String title, Function<ObjectOutputStream> consumer) throws Exception {
        System.out.println(title+":");

        StringWriter s = new StringWriter();

        ObjectOutputStream oos = new ObjectOutputStream(new HexOutputStream(s));

        consumer.apply(oos);

        oos.flush();

        oos.close();

        System.out.println(s.toString()+"\n");
    }

    public interface Function<T> {
        void apply(T t) throws Exception;
    }

    /**
     * @see com.sun.corba.se.impl.orbutil
     * Got this class for hex dump with some changes.
     */
    public static class HexOutputStream extends OutputStream
    {
        public static final int PADDING = 16;

        protected char[] row = new char[PADDING];

        static private final char hex[] = {
            '0', '1', '2', '3', '4', '5', '6', '7',
            '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
        };

        private StringWriter writer;

        private long offset = 0;

        /**
         * Creates a new HexOutputStream.
         * @param w The underlying StringWriter.
         */
        public
        HexOutputStream(StringWriter w) {
            writer = w;
        }


        /**
         * Writes a byte. Will block until the byte is actually
         * written.
         * param b The byte to write out.
         * @exception java.io.IOException I/O error occurred.
         */
        public synchronized void write(int b) throws IOException {
            if (offset % PADDING == 0) {
                for (int i=4*2;i>=0;i--) {
                    int tmpOffset = (int)(offset >> i*4);

                    writer.write(hex[((tmpOffset) & 0xF)]);
                }
                writer.write(": ");
            }

            writer.write(hex[((b >> 4) & 0xF)]);
            writer.write(hex[((b >> 0) & 0xF)]);

            offset++;

            row[(int)((offset-1) % PADDING)] = (char)b;

            if (offset % PADDING == 0) {
                writer.write(" | ");

                //for (int i=0;i<row.length;i++) {
                    writer.write(row);
                //}

                writer.write("\n");
            } else {
                writer.write(" ");
            }
        }

        @Override
        public void close() throws IOException {
            //System.out.print(">>"+offset % PADDING);

            if (offset % PADDING < PADDING) {
                for (int i=(int)(offset % PADDING);i<PADDING;i++) {
                    writer.append("   ");
                }

                writer.write("| ");

                writer.write(row, 0, (int)(offset % PADDING));
            }

            super.close();
        }

        public synchronized void write(byte[] b) throws IOException {
            write(b, 0, b.length);
        }

        public synchronized void write(byte[] b, int off, int len)
            throws IOException
        {
            for(int i=0; i < len; i++) {
                write(b[off + i]);
            }
        }
    }
}

Пример запуска

$ java -cp build/classes/ test.serialize.TestSerialize 
Boolean(true):
000000000: ac ed 00 05 77 01 01                            | ᆲ■ w

Boolean(false):
000000000: ac ed 00 05 77 01 00                            | ᆲ■ w 

Byte(0x11):
000000000: ac ed 00 05 77 01 11                            | ᆲ■ w

Bytes(ab):
000000000: ac ed 00 05 77 02 61 62                         | ᆲ■ wab

Char(z):
000000000: ac ed 00 05 77 02 00 7a                         | ᆲ■ w z

Chars(abc):
000000000: ac ed 00 05 77 06 00 61 00 62 00 63             | ᆲ■ w a b c

Int(1234):
000000000: ac ed 00 05 77 04 00 00 04 d2                   | ᆲ■ w  ᅭ

Long(1234):
000000000: ac ed 00 05 77 08 00 00 00 00 00 00 04 d2       | ᆲ■       ᅭ

Short(1234):
000000000: ac ed 00 05 77 02 04 d2                         | ᆲ■ wᅭ

Object(a):
000000000: ac ed 00 05 74 00 01 61                         | ᆲ■ t a

Object(п):
000000000: ac ed 00 05 74 00 02 d0 bf                      | ᆲ■ t ￐﾿

Object(new HashMap<>()):
000000000: ac ed 00 05 73 72 00 11 6a 61 76 61 2e 75 74 69 | ᆲ■ sr java.uti
000000010: 6c 2e 48 61 73 68 4d 61 70 05 07 da c1 c3 16 60 | l.HashMapᅳ￁ᅢ`
000000020: d1 03 00 02 46 00 0a 6c 6f 61 64 46 61 63 74 6f | ￑ F 
loadFacto
000000030: 72 49 00 09 74 68 72 65 73 68 6f 6c 64 78 70 3f | rI 	thresholdxp?
000000040: 40 00 00 00 00 00 00 77 08 00 00 00 10 00 00 00 | @            
000000050: 00 78                                           |  x

Object(new Cls1):
000000000: ac ed 00 05 73 72 00 18 74 65 73 74 2e 73 65 72 | ᆲ■ sr test.ser
000000010: 69 61 6c 69 7a 65 2e 4d 61 69 6e 24 43 6c 73 31 | ialize.Main$Cls1
000000020: 4d 22 c3 b4 41 00 bf 41 02 00 01 4c 00 03 76 61 | M"ᅢᄡA ﾿A L va
000000030: 6c 74 00 10 4c 6a 61 76 61 2f 6c 61 6e 67 2f 4c | lt Ljava/lang/L
000000040: 6f 6e 67 3b 78 70 73 72 00 0e 6a 61 76 61 2e 6c | ong;xpsr java.l
000000050: 61 6e 67 2e 4c 6f 6e 67 3b 8b e4 90 cc 8f 23 df | ang.Long;ヒ¦ミᅩマ#￟
000000060: 02 00 01 4a 00 05 76 61 6c 75 65 78 72 00 10 6a |  J valuexr j
000000070: 61 76 61 2e 6c 61 6e 67 2e 4e 75 6d 62 65 72 86 | ava.lang.Numberニ
000000080: ac 95 1d 0b 94 e0 8b 02 00 00 78 70 00 00 00 00 | ᆲユヤ¢ヒ  xp    
000000090: 00 00 00 7b                                     |    {

Object(new Cls2):
000000000: ac ed 00 05 73 72 00 18 74 65 73 74 2e 73 65 72 | ᆲ■ sr test.ser
000000010: 69 61 6c 69 7a 65 2e 4d 61 69 6e 24 43 6c 73 32 | ialize.Main$Cls2
000000020: 5b 34 53 26 2c d5 84 5a 02 00 01 4c 00 04 76 61 | [4S&,ᅰトZ L va
000000030: 6c 32 74 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f | l2t Ljava/lang/
000000040: 53 74 72 69 6e 67 3b 78 72 00 18 74 65 73 74 2e | String;xr test.
000000050: 73 65 72 69 61 6c 69 7a 65 2e 4d 61 69 6e 24 43 | serialize.Main$C
000000060: 6c 73 31 4d 22 c3 b4 41 00 bf 41 02 00 01 4c 00 | ls1M"ᅢᄡA ﾿A L 
000000070: 03 76 61 6c 74 00 10 4c 6a 61 76 61 2f 6c 61 6e | valt Ljava/lan
000000080: 67 2f 4c 6f 6e 67 3b 78 70 73 72 00 0e 6a 61 76 | g/Long;xpsr jav
000000090: 61 2e 6c 61 6e 67 2e 4c 6f 6e 67 3b 8b e4 90 cc | a.lang.Long;ヒ¦ミᅩ
0000000a0: 8f 23 df 02 00 01 4a 00 05 76 61 6c 75 65 78 72 | マ#￟ J valuexr
0000000b0: 00 10 6a 61 76 61 2e 6c 61 6e 67 2e 4e 75 6d 62 |  java.lang.Numb
0000000c0: 65 72 86 ac 95 1d 0b 94 e0 8b 02 00 00 78 70 00 | erニᆲユヤ¢ヒ  xp 
0000000d0: 00 00 00 00 00 00 7b 74 00 0b 54 65 73 74 20 73 |       {t Test s
0000000e0: 74 72 69 6e 67                                  | tring

Decode by hands

000000000: ac ed  - magic
000000000:       00 05  - stream version
000000000:             7e - TC_ENUM 
000000000:                72 - TC_CLASS_DESC 
000000000:                   00 1a - length = 26 
000000000:                         74 65 73 74 2e 73 65 72 | test.ser

000000010: 69 61 6c 69 7a 65 2e 4d 61 69 6e 24 4d 79 45 6e | ialize.Main$MyEn

000000020: 75 6d | um
000000020:       00 00 00 00 00 00 00 00 - serial version uid
000000020:                               12  - Flags?
000000020:                                  00 00 - fields count 
000000020:                                        78 - end block data for class annotation 
000000020:                                           72 - super class class desc
000000020:                                              00 - start of length of class

000000030: 0e - length = 14
000000030:    6a 61 76 61 2e 6c 61 6e 67 2e 45 6e 75 6d |java.lang.Enum
000000030:                                              00 - start of serial version id

000000040: 00 00 00 00 00 00 00 - serial version id
000000040:                      12 - flags 
000000040:                         00 00 - field count 0 
000000040:                               78 - end block data 
000000040:                                  70 - TC_NULL
000000040:                                     74 - TC_STRING 
000000040:                                        00 06 -- string length 
000000040:                                              56 - name | V

000000050: 41 4c 55 45 32                                  | ALUE2
Clone this wiki locally