seasonouc / protostuff

Automatically exported from code.google.com/p/protostuff
Apache License 2.0
0 stars 0 forks source link

protostuff has problem to serialize java.lang.Throwable Object #115

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
1.Use ProtostuffRuntime and GraphIOUtil to serialize java.lang.Throwable Object

2.Considering com.good.ExceptionAAA has a cause named com.good.ExceptionBBB( 
new ExptionAAA("wrapperError",exceptionBBB) ), Protustuff can serialize the 
ExceptionAAA rightly. But when it deserialize ExceptionAAA, the cause of 
ExceptionAAA will become java.lang.Throwable not com.good.ExceptionBBB

What version of the product are you using? On what operating system?
protostuff 1.0.5
jdk 1.6

Is it possible that protoStuff can process java.lang.Throwble seperately but 
not using GraphIOUtil? 
GraphIOUtil seem to be have bad performance to process normal java object.

Original issue reported on code.google.com by tully...@gmail.com on 25 Apr 2012 at 9:45

GoogleCodeExporter commented 8 years ago
If you can attach a simple testcase, that would be great.

Original comment by david.yu...@gmail.com on 25 Apr 2012 at 10:01

GoogleCodeExporter commented 8 years ago
It seem to ProtoStuff can not cast the subClass rightly.
If there is a SuperClassCCC and a SubClassDDD (SubClassDDD extends 
SuperClassCCC) and the pojo has a field declared by SuperClassCCC, the field of 
pojo will be setted to SubClassDDD. 
After deserializion, the field of new pojo will be SuperClassCCC not 
SubClassDDD.

So the information of SubClass will be ignored by ProtoStuff .

Original comment by tully...@gmail.com on 25 Apr 2012 at 10:01

GoogleCodeExporter commented 8 years ago
You might have missed this on the wiki 
(http://code.google.com/p/protostuff/wiki/ThingsYouNeedToKnow)

-Dprotostuff.runtime.morph_non_final_pojos=true

The side effect is that your other non-final pojos (even if there aren't any 
subtypes) will be serialized with type metadata.

The workaround to that is simply making it final (no subtypes anyway)

Original comment by david.yu...@gmail.com on 25 Apr 2012 at 10:15

GoogleCodeExporter commented 8 years ago
the testcase is fllowing:

import org.junit.Test;

import com.dyuproject.protostuff.GraphIOUtil;
import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;

public class TestSer {
    public static class ExceptionA extends RuntimeException {

        private static final long serialVersionUID = 2960474892574945398L;

        public ExceptionA(String message, Throwable cause) {
            super(message, cause);
        }

        public ExceptionA(String message) {
            super(message);
        }

        public ExceptionA() {
            super();
        }
    }

    public static class ExceptionB extends RuntimeException {

        private static final long serialVersionUID = 5191284136041381488L;

        public ExceptionB(String message, Throwable cause) {
            super(message, cause);
        }

        public ExceptionB(String message) {
            super(message);
        }
    }

    public static class Wrapper {

        public Object getError() {
            return error;
        }

        public void setError(Object error) {
            this.error = error;
        }

        private Object error;

    }

    @Test
    public void testSerException1() {
        ExceptionB expB = new ExceptionB("ExceptionB");
        ExceptionA expA = new ExceptionA("ExceptionA", expB);
        Schema<ExceptionA> schema = RuntimeSchema.getSchema(ExceptionA.class);
        System.out.println(expA.getCause());
        // output TestSer$ExceptionB: ExceptionB
        byte[] data = GraphIOUtil.toByteArray(expA, schema, LinkedBuffer.allocate(500));

        ExceptionA cf = new ExceptionA();
        GraphIOUtil.mergeFrom(data, cf, schema);
        System.out.println(cf.getCause());// output null
    }

    @Test
    public void testSerException2() {
        ExceptionB expB = new ExceptionB("ExceptionB");
        ExceptionA expA = new ExceptionA("ExceptionA", expB);
        Wrapper wrapper = new Wrapper();
        wrapper.setError(expA);
        Schema<Wrapper> schema = RuntimeSchema.getSchema(Wrapper.class);
        System.out.println(((ExceptionA) wrapper.getError()).getCause());
        // output TestSer$ExceptionB: ExceptionB
        byte[] data = GraphIOUtil.toByteArray(wrapper, schema, LinkedBuffer.allocate(500));

        Wrapper wrappernew = new Wrapper();
        GraphIOUtil.mergeFrom(data, wrappernew, schema);
        System.out.println(((ExceptionA) wrappernew.getError()).getCause());// output
                                                                            // null
    }
}

Original comment by tully...@gmail.com on 25 Apr 2012 at 10:55

GoogleCodeExporter commented 8 years ago
And there is more strange case:

public static class ExceptionAA extends ExceptionA {

        private static final long serialVersionUID = 2960474892574945391L;

        public ExceptionAA(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public static class ExceptionAAA extends ExceptionAA {

        private static final long serialVersionUID = 2960474892574945394L;

        public ExceptionAAA(String message, Throwable cause) {
            super(message, cause);
        }
    }

    @Test
    public void testSerException3() {
        ExceptionB expB = new ExceptionB("ExceptionB");
        ExceptionAAA expA = new ExceptionAAA("ExceptionBiz", expB);
        Wrapper wrapper = new Wrapper();
        wrapper.setError(expA);
        Schema<Wrapper> schema = RuntimeSchema.getSchema(Wrapper.class);
        System.out.println(((ExceptionAAA) wrapper.getError()).getCause());
        // output TestSer$ExceptionB: ExceptionB
        byte[] data = GraphIOUtil.toByteArray(wrapper, schema, LinkedBuffer.allocate(500));

        Wrapper wrappernew = new Wrapper();
        GraphIOUtil.mergeFrom(data, wrappernew, schema);
        System.out.println(((ExceptionAAA) wrappernew.getError()).getCause());// output
        // java.lang.Throwable: ExceptionB
    }

Original comment by tully...@gmail.com on 25 Apr 2012 at 11:18

GoogleCodeExporter commented 8 years ago
Add the snippet below:

    static
    {
        System.setProperty("protostuff.runtime.morph_non_final_pojos", "true");
    }

It is false by default (Some devs have the habit of not using the final 
keyword).
I'll consider enabling that by default for 1.0.6.

Original comment by david.yu...@gmail.com on 25 Apr 2012 at 11:49

GoogleCodeExporter commented 8 years ago
It works. But I think protostuff should have something like ThrowableSerializer 
and  ThrowableDeserializer  to process Throwable object

Original comment by tully...@gmail.com on 25 Apr 2012 at 11:58

GoogleCodeExporter commented 8 years ago
Makes sense.  Code shall detect Throwable and make sure POLYMORPHIC_POJO is 
used.

Original comment by david.yu...@gmail.com on 25 Apr 2012 at 1:16

GoogleCodeExporter commented 8 years ago
And this way can avoid using GraphIOUtil to process Throwable. Mostly we will 
not design cyclic references object.

Original comment by tully...@gmail.com on 26 Apr 2012 at 6:52

GoogleCodeExporter commented 8 years ago
fixed @ rev 1520.
Throwables can now be serialized without using GraphIOUtil.

Original comment by david.yu...@gmail.com on 2 May 2012 at 7:33