Java 使用 Hessian2 序列化和反序列化


#Java 笔记


Hessian2 是一个通用的序列化框架,官方文档:http://hessian.caucho.com/doc/hessian-serialization.html

基础示例

若使用 gradle 构建 Java 项目,请在 build.gradle 中增加以下依赖:

compile group: 'com.caucho', name: 'hessian', version: '4.0.60'

本文的示例用了lombok 和 junit,所以 build.gradle 中依赖配置如下:

compile group: 'com.caucho', name: 'hessian', version: '4.0.60'
compile group: 'org.projectlombok', name: 'lombok', version: '1.18.0' // lombok 依赖
compile group: 'junit', name: 'junit', version: '4.12'

编写 Hessian2 的工具类:

package demo;

import com.caucho.hessian.io.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class HessianUtil {

    // 序列化
    public static byte[] serialize(Object obj) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        AbstractHessianOutput out = new Hessian2Output(os);

        out.setSerializerFactory(new SerializerFactory());
        try {
            out.writeObject(obj);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                out.close();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return os.toByteArray();
    }

    // 反序列化
    public static <T> T deserialize(byte[] bytes) {
        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
        AbstractHessianInput in = new Hessian2Input(is);

        in.setSerializerFactory(new SerializerFactory());
        T value;
        try {
            value = (T) in.readObject();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                in.close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return value;
    }

}

示例1:序列化

编写 Java Bean:

package demo;

import lombok.Data;
import lombok.ToString;

import java.io.Serializable;

@Data
@ToString
public class Person implements Serializable {

    private String name;
    private int age;

    public Person() {

    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

}

序列化示例:

Person person = new Person("letian", 18);

// 序列化
byte[] bytes = HessianUtil.serialize(person);

// 输出数字,看长什么样子
for (byte i : bytes) {
    System.out.printf("%s ", i);
}
System.out.println();

// 输出字符,看长什么样子(注意,数字转字符,有些会比较奇怪,有些字符是不可见的)
for (byte i : bytes) {
    System.out.printf("%s", (char)i);
}
System.out.println();

运行结果:

67 11 100 101 109 111 46 80 101 114 115 111 110 -110 4 110 97 109 101 3 97 103 101 96 6 108 101 116 105 97 110 -94 
Cdemo.Personメnameage`letianᄁ

示例2:反序列化

Person person = new Person("letian", 18);

// 序列化
byte[] bytes = HessianUtil.serialize(person);

// 反序列化
Person person2 = HessianUtil.deserialize(bytes);
System.out.println(person2);

运行结果:

Person(name=letian, age=18)

示例3:复杂 Java Bean 的序列化和反序列化

我把一个含有其他 Java Bean 的 Java Bean 叫做 复杂Java bean 。

package demo;

import lombok.Data;

import java.io.Serializable;

@Data
public class Address implements Serializable {

    private String city;

    public Address() {

    }

    public Address(String city) {
        this.city = city;
    }

}
package demo;

import lombok.Data;

import java.io.Serializable;

@Data
public class Student implements Serializable {

    private String name;

    private int age;

    private Address address;

    public Student() {

    }

    public Student(String name, int age, Address address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

}

这里,Student 是一个复杂类型,序列化和反序列化示例如下:

Student student = new Student("letian", 18, new Address("test"));

// 序列化
byte[] bytes = HessianUtil.serialize(student);

// 输出数字,看长什么样子
for (byte i : bytes) {
    System.out.printf("%s ", i);
}
System.out.println();

// 输出字符,看长什么样子(注意,数字转字符,有些会比较奇怪,有些字符是不可见的)
for (byte i : bytes) {
    System.out.printf("%s", (char)i);
}
System.out.println();

// 反序列化
Student student1 = HessianUtil.deserialize(bytes);
System.out.println("反序列化结果:" + student1);

运行结果:

67 12 100 101 109 111 46 83 116 117 100 101 110 116 -109 4 110 97 109 101 3 97 103 101 7 97 100 100 114 101 115 115 96 6 108 101 116 105 97 110 -94 67 12 100 101 109 111 46 65 100 100 114 101 115 115 -111 4 99 105 116 121 97 4 116 101 115 116 
Cdemo.Studentモnameageaddress`letianᄁCdemo.Addressムcityatest
反序列化结果:Student(name=letian, age=18, address=Address(city=test))

示例4:泛型 Java Bean 的序列化和反序列化

下面是一个使用了泛型的 Java Bean:

package demo;

import lombok.Data;

import java.io.Serializable;

@Data
public class Response<T> implements Serializable {

    private Boolean success;

    private T data;

    public Response() {

    }

    public Response(Boolean success, T data) {
        this.success = success;
        this.data = data;
    }

}

序列化和反序列化示例:

Student student = new Student("letian", 18, new Address("test"));
Response<Student> response = new Response<>(true, student);

// 序列化
byte[] bytes = HessianUtil.serialize(response);

// 输出数字,看长什么样子
for (byte i : bytes) {
    System.out.printf("%s ", i);
}
System.out.println();

// 输出字符,看长什么样子(注意,数字转字符,有些会比较奇怪,有些字符是不可见的)
for (byte i : bytes) {
    System.out.printf("%s", (char)i);
}
System.out.println();

// 反序列化
Response<Student> response1 = HessianUtil.deserialize(bytes);
System.out.println("反序列化结果:" + response1);

Java 的泛型是伪泛型,如果使用不当,会在运行时报错,比如:

Student student = new Student("letian", 18, new Address("test"));
Response<Student> response = new Response<>(true, student);

// 序列化
byte[] bytes = HessianUtil.serialize(response);

// 反序列化,注意,这里泛型用的 Address
Response<Address> response1 = HessianUtil.deserialize(bytes);

// 这里不会报错
System.out.println(response1);

// 这里会报错
System.out.println(response1.getData().getCity());

执行结果如下:

Response(success=true, data=Student(name=letian, age=18, address=Address(city=test)))

java.lang.ClassCastException: demo.Student cannot be cast to demo.Address
    ......


( 本文完 )