Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added hprose serialization support. #162

Merged
merged 5 commits into from
Aug 12, 2016
Merged

Added hprose serialization support. #162

merged 5 commits into from
Aug 12, 2016

Conversation

andot
Copy link
Contributor

@andot andot commented Jul 30, 2016

这个仅仅是添加了 Hprose 序列化支持,跟 hessian2、fastjson 一样。

@rayzhang0603
Copy link
Collaborator

非常感谢,我们会尽快进行测试

@andot
Copy link
Contributor Author

andot commented Aug 8, 2016

谢谢,hprose 远程调用协议跟 motan 的适配好像有点麻烦,还没看明白该怎么做,所以这个只是序列化的。如果能够把反序列化接口改成支持泛型的 Type(替换 Class),效果会更好一些。不过好像比较难改。


@Override
public byte[] serialize(Object data) throws IOException {
ByteBufferStream stream = HproseFormatter.serialize(data);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

有很多java bean对象的属性都是私有的,这里是不是可以这样修改?

ByteBufferStream stream = HproseFormatter.serialize(data, HproseMode.FieldMode, false);

@rayzhang0603
Copy link
Collaborator

@andot 我发现hprose序列化时有个local的cache,用来缓存上一次序列化的对象,当对象的属性值修改后再次序列化时,还会使用缓存的byte[],相当于修改没有生效。见HproseFormatter类

 Cache c = cache.get();
    if ((c != null) &&
        (obj == c.obj) &&
        (mode == c.mode) &&
        (simple == c.simple)) {
        bufstream.write(c.buffer);
        return bufstream;
    }

可以试一下下面的例子

@Test
public void testModify() throws Exception{
    TestModel model = new TestModel();
    model.setName("xxx");
    Serialization s = new HproseSerialization();
    TestModel result = s.deserialize(s.serialize(model), TestModel.class);
    assertEquals(model.getName(), result.getName());

    model.setName("yyy");
    result = s.deserialize(s.serialize(model), TestModel.class);
    assertEquals(model.getName(), result.getName());
}

class TestModel{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

@andot
Copy link
Contributor Author

andot commented Aug 11, 2016

默认用 HproseMode.MemberMode 是为了跨语言,HproseMode.FieldMode 适合纯 Java 之间传输。因为私有字段的名字在跨语言方面是个障碍,比如对于不知道实现的人来说,私有字段是什么样的不好确定,也可能私有字段名会定义的很乱。而且私有字段在继承关系中,如果有同名字段,也会导致序列化结果不正确。所以,Hprose 推荐用户在定义需要传输的类型时,对于需要封装的属性,用 getter 和 setter,对于不需要封装的属性,可以用 getter 和 setter,也可以用 public 的字段,而且这样定义的类,也不要求必须实现 Serializable 接口了。这就是 MemberMode 的由来。

至于那个 ThreadLocal 的 cache,确实没想到会导致这个问题。因为在 hprose 的 rpc 中,并没有使用这个 HproseFormatter 类,而是直接使用的 HproseWriter 和 HproseReader。我可以把这块改成也使用 HproseWriter 和 HproseReader 来进行序列化反序列化,就不会有这个问题了。

@rayzhang0603
Copy link
Collaborator

@andot 功能已经测试完了,没有问题。
serialize方法,如果writer.serialize()发生异常,会导致stream中的DirectByteBuffer无法回收到ByteBufferPool中,也不会触发Cleaner回收,有堆外内存泄漏的风险,我觉得可以改成这样:

ByteBufferStream stream = null;
    try{
        stream = new ByteBufferStream();
        HproseWriter writer = new HproseWriter(stream.getOutputStream());
        writer.serialize(data);
        byte[] result = stream.toArray();
        return result;
    }finally{
        if(stream != null){
            stream.close();
        }
    }

@andot
Copy link
Contributor Author

andot commented Aug 12, 2016

@rayzhang0603 非常感谢,已修改。

@rayzhang0603 rayzhang0603 merged commit 0994fb2 into weibocom:master Aug 12, 2016
@rayzhang0603
Copy link
Collaborator

非常感谢!

@qdaxb
Copy link
Collaborator

qdaxb commented Aug 12, 2016

文档需要更新一下。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants