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

protostuff loses the type when serializing the subtype #8742

Closed
2 tasks
xiaoheng1 opened this issue Sep 9, 2021 · 14 comments
Closed
2 tasks

protostuff loses the type when serializing the subtype #8742

xiaoheng1 opened this issue Sep 9, 2021 · 14 comments

Comments

@xiaoheng1
Copy link
Contributor

xiaoheng1 commented Sep 9, 2021

  • I have searched the issues of this repository and believe that this is not a duplicate.
  • I have checked the FAQ of this repository and believe that this is not a duplicate.

Environment

  • Dubbo version: dubbo3+
  • Operating System version: macos
  • Java version: 11

Steps to reproduce this issue

test case:

public class Main {
    
    public static void main(String[] args) {
    
        URL data = URL.valueOf("dubbo://100:zzzzz@10.20.130.230:20880/context/path?version=1.0.0&application=morgan&noValue=z");
        Schema<URL> schema = RuntimeSchema.getSchema(URL.class);
    
        // Re-use (manage) this buffer to avoid allocating on every serialization
        LinkedBuffer buffer = LinkedBuffer.allocate(512);
    
        // ser
        final byte[] protostuff;
        try
        {
            protostuff = ProtostuffIOUtil.toByteArray(data, schema, buffer);
        }
        finally
        {
            buffer.clear();
        }
    
        // deser
        URL fooParsed = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(protostuff, fooParsed, schema);
    
        System.out.println(fooParsed);
        
      
    }
}

link protostuff/protostuff#316

@zrlw
Copy link
Contributor

zrlw commented Sep 12, 2021

application和version都是URL存储在Global Param Cache Table里的参数,URL.valueOf构造的URLParam不会存储这些参数,只是通过一个BitSet指向DynamicParamTable对应的index。
你这种场景需要对valueOf构建出来的URL再加一次toSerializableURL()转换,再加上morphNonFinalPojosStrategy策略:

        URL data = URL.valueOf("blah blah").toSerializableURL();
        DefaultIdStrategy morphNonFinalPojosStrategy = new DefaultIdStrategy(
                IdStrategy.DEFAULT_FLAGS | IdStrategy.MORPH_NON_FINAL_POJOS, null, 0);
        Schema<URL> schema = RuntimeSchema.getSchema(URL.class, morphNonFinalPojosStrategy);

@xiaoheng1
Copy link
Contributor Author

application和version都是URL存储在Global Param Cache Table里的参数,URL.valueOf构造的URLParam不会存储这些参数,只是通过一个BitSet指向DynamicParamTable对应的index。
你这种场景需要对valueOf构建出来的URL再加一次toSerializableURL()转换,再加上morphNonFinalPojosStrategy策略:

        URL data = URL.valueOf("blah blah").toSerializableURL();
        DefaultIdStrategy morphNonFinalPojosStrategy = new DefaultIdStrategy(
                IdStrategy.DEFAULT_FLAGS | IdStrategy.MORPH_NON_FINAL_POJOS, null, 0);
        Schema<URL> schema = RuntimeSchema.getSchema(URL.class, morphNonFinalPojosStrategy);

这样弄了也解决不了,你可以试下,反序列化后的值和序列化之前的值不一样

@xiaoheng1
Copy link
Contributor Author

在我本机测试时发现,反序列化后的值的 toString 固定了,用的是 URLAddress 的属性(实际上应该要用它的子类才对)

@zrlw
Copy link
Contributor

zrlw commented Sep 13, 2021

fooParsed.toFullString():
dubbo://100:zzzzz@10.20.130.230:20880/context/path?application=morgan&noValue=z&version=1.0.0
只是顺序发生了变化而已。
你可能是对URL这个类不是很了解,不是所有的类默认都支持protostuff,如果你坚持使用protostuff做序列化,需要先搞清楚你使用的类是否对所有属性都做了默认序列化,如果没有,需要自己去定制,就像URL的toFullString和toSerializableURL方法那样自己去实现。

@xiaoheng1
Copy link
Contributor Author

感谢,我好像明白了。
我觉得 dubbo 应该是需要支持 URL 的序列化的,但是我对 protostuff 这个不太熟,不知道在 ProtostuffObjectInput、ProtostuffObjectOutput 引入 DefaultIdStrategy 这个是否会有影响。能否帮忙看看
目前 protostuff 这个的序列化是放在 spi-extension 仓库那边的。

@zrlw
Copy link
Contributor

zrlw commented Sep 13, 2021

URL应该不是为了你这种应用场景设计的,你不需要URL,只需要一个承载URL的字符串,直接传url的字符串就好了,然后用URL.valueOf重新构造出来。
最多再加个包装类,比如:

public class MyURL implements Serializable  {
        private static final long serialVersionUID = 1L;
        private String url;
        public MyURL(String url) {
            this.url = url;
        }
        public URL getUrl() {
            return URL.valueOf(url);
        }
        @Override
        public String toString() {
            return url;
        }
        @Override
        public int hashCode() {
            return Objects.hash(url);
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (obj == null) {
                return false;
            }
            if (!(obj instanceof MyURL)) {
                return false;
            }
            MyURL other = (MyURL) obj;
            return Objects.equals(this.getUrl(), other.getUrl());
        }
}

@xiaoheng1
Copy link
Contributor Author

我是觉得应该还是要支持 URL 的序列化,在 dubbo2 中,有相关的测试用例. 现在在 dubbo3 中迁移到了 spi-extension 仓库中了。然后经过测试,发现 protostuff 对于序列化 URL 的用例跑不过

@zrlw
Copy link
Contributor

zrlw commented Sep 13, 2021

3.0和2.0的URL差异很大,3.0的url参数搞了个全局存储,可能是为了兼容2.0的功能,又加了个toFullString和toSerializableURL,不清楚这么搞是不是为了提高性能,但是这样做的结果就是3.0的URL根本支持不了你这种应用场景了。

@zrlw
Copy link
Contributor

zrlw commented Sep 13, 2021

还有一个就是3.0的URL里面的URLAddress,URLParam属性字段类型都是基类,实际使用的类型可能都是派生类,RuntimeSchema.getSchema(URL.class)这样获取的schema是搞不定原样反序列化的。

@xiaoheng1
Copy link
Contributor Author

是的,所以我的想法是吧 RuntimeSchema.getSchema(URL.class) 这个修改 为 RuntimeSchema.getSchema(Class, DefaultIdStrategy) 为这种,但是不知道是否会影响其他类型的序列化

@zrlw
Copy link
Contributor

zrlw commented Sep 14, 2021

有派生类的情况下通常都需要设置这个参数,对性能有影响,如果你追求完美,还可以自定义序列化delegate

@xiaoheng1
Copy link
Contributor Author

明白了,感谢

@zrlw
Copy link
Contributor

zrlw commented Sep 14, 2021

我在dubbo-spi-extentsions提了个PR,可以参考一下
apache/dubbo-spi-extensions#67

@zrlw
Copy link
Contributor

zrlw commented Nov 13, 2023

两年前提交的 apache/dubbo-spi-extensions#67 居然今天收到了fix conficts的回应,我都忘了当初提这个PR是要修复什么东西了,找到这个帖子才想起来。

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

No branches or pull requests

2 participants