在java中,如何序列化未标记为Serializable的类?

时间:2010-01-22 00:55:41

标签: java reflection serialization

我想要序列化第三方库中的特定类。我该怎么做呢?

我假设我必须编写一个方法来接受类的对象并使用反射来获取私有成员值。然后,为了反序列化,我会使用反射来放回值。

这会有用吗?有没有更简单的方法?

4 个答案:

答案 0 :(得分:13)

您可以使用实现Serializable的传输对象,并且具有与第三方对象相同的字段。让传输对象实现一个方法,该方法返回原始第三方类的对象并完成:

伪代码:

class ThirdParty{

    int field1;
    int field2;
}

class Transfer implements Serializable{

    int field1;
    int field2;

    /* Constructor takes the third party object as 
       an argument for copying the field values.
       For private fields without getters 
       use reflection to get the values */
    Transfer (ThirdParty orig){
       this.field1=orig.field1;
       this.field2=orig.field2;
    }

    ThirdParty getAsThirdParty(){
        ThirdParty copy=new ThirdParty();
        copy.field1=this.field1;
        copy.field2=this.field2;
        return copy;
    }

    /* override these methods for custom serialization */
    void writeObject(OutputStream sink);
    void readObject(InputStream src);
}

如果你有任何特殊的成员对象,你必须确保成员被正确序列化。

或者,如果第三方类不是final,你可以扩展它,让它实现Serializable并编写你自己的writeObject和readObject方法。

点击此处查看一些序列化信息:

Serialization Secrets

答案 1 :(得分:2)

您需要将其包装成可进行序列化的内容。

理想情况下,第三方类支持其他形式的序列化,例如XML序列化(基于bean属性)。如果没有,你必须自己动手。无论是涉及反射还是只是吸气剂,设定者和构造者都取决于阶级。

在任何情况下,包装器都会将对象转换为byte []或String或其他内容,并将其写入序列化输出。在反序列化时,它从该数据重建对象。

您的包装器必须实现的两种方法是

private void writeObject(java.io.ObjectOutputStream out)
 throws IOException
private void readObject(java.io.ObjectInputStream in)
 throws IOException, ClassNotFoundException;

答案 2 :(得分:1)

很大程度上取决于第三方课程的性质。它是最终的,是否有一个无参数构造函数,你可以根据已知值构造它,还是由另一个类构造,它本身是否包含非Serializable成员?

最简单的方法是对类进行反编译,添加一个实现Serializable,然后重新编译它,但如果它包含非Serializable成员,事情会变得更复杂。

答案 3 :(得分:1)

另一种可能的解决方案可能是在Serializable类中定义一组私有方法,这些方法使用第三方类的实例。这些特殊方法是序列化系统提供的特殊回调契约的一部分。这些方法将在调用期间调用。序列化/反序列化过程。 他们的签名必须如下:

private void writeObject(ObjectOutputStream os) {
// your code for saving the third party variables
}
private void readObject(ObjectInputStream is) {
// your code to read the third party state, create a new ThirdParty instance,
// and assign it to your class.
}

这个例子进一步澄清了这个想法:

public class MyClass implements Serializable 
{
   transient private ThirdParty thirdPartyInstance ;
    private int  myClassVariable ;
    private void writeObject(ObjectOutputStream oos)
    {
        try
        {

            oos.defaultWriteObject();
            oos.writeInt(thirdPartyInstance.getThirdPartyVariable());
            oos.writeInt(thirdPartyInstance.getFourthPartyInstance().getFourthPartyVariable());
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    private void readObject(ObjectInputStream ois)
    {
        try
        {
            ois.defaultReadObject(); //the call to defaultReadObject method must always be before any other code in the try block

            //Reconstructing thirdPartyInstance 
thirdPartyInstance =new ThirdParty(ois.readInt(),new FourthParty(ois.readInt()));

        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    MyClass(int myClassVariable, ThirdParty thirdPartyInstance)
    {
        this.myClassVariable=myClassVariable;
        this.thirdPartyInstance=thirdPartyInstance;
    }
    ThirdParty getThirdPartyInstance()
    {
        return thirdPartyInstance;
    }

    int getMyClassVariable()
    {
        return myClassVariable;
    }

    public static void main(String args[])
    {
        FourthParty fourthPartyInstance=new FourthParty(45);
        ThirdParty thirdPartyInstance=new ThirdParty(13,fourthPartyInstance);
        MyClass myClassInstance=new MyClass(7,thirdPartyInstance);
        System.out.println("Before: ThirdParty variable value is "+myClassInstance.getThirdPartyInstance().getThirdPartyVariable());
        System.out.println("Before: FourthParty variable value is "+myClassInstance.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable());
        System.out.println("Before: MyClass variable value is "+myClassInstance.getMyClassVariable());
        try
        {       
            FileOutputStream fios=new FileOutputStream("D://TestFileq.ser");
            ObjectOutputStream oos=new ObjectOutputStream(fios);
            oos.writeObject(myClassInstance);
            oos.close();


            FileInputStream fi = new FileInputStream("D://TestFileq.ser");
            ObjectInputStream objectIn = new ObjectInputStream(fi);
            MyClass myClassInst = (MyClass)objectIn.readObject();
            System.out.println("After: ThirdParty variable value is "+myClassInst.getThirdPartyInstance().getThirdPartyVariable());
            System.out.println("After: FourthParty variable value is "+myClassInst.getThirdPartyInstance().getFourthPartyInstance().getFourthPartyVariable());
            System.out.println("After:MyClass variable value is  "+myClassInst.getMyClassVariable());

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

    }

}
class ThirdParty
{
    private int thirdPartyVariable;
    private FourthParty fourthPartyInstance;
    ThirdParty(int thirdPartyVariable,FourthParty fourthPartyInstance)
    {
        this.thirdPartyVariable=thirdPartyVariable;
        this.fourthPartyInstance=fourthPartyInstance;
    }
    int getThirdPartyVariable()
    {
        return thirdPartyVariable;
    }
    FourthParty getFourthPartyInstance()
    {
        return fourthPartyInstance;
    }


}
class FourthParty
{
    private int fourthPartyVariable;
    FourthParty(int fourthPartyVariable)
    {
        this.fourthPartyVariable=fourthPartyVariable;
    }
    int getFourthPartyVariable()
    {
        return fourthPartyVariable;
    }


}

请注意,MyClass中的thirdPartyInstance必须声明为transient,否则为类型' java.io.NotSerializableException'发生。 有关更多说明,请参阅 SCJP Sun认证Java 6程序员,Cathy Sierra',第497页