Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In java how do I serialize a class that is not marked Serializable?

There is a specific class in a third party library that I want to serialize. How would I go about doing this?

I'm assuming I will have to write a method that takes in an object of the class and uses reflection to get the private member values. Then for deserialization I would use reflection to put the values back.

Would this work? Is there an easier way?

like image 643
Kyle Avatar asked Jan 22 '10 00:01

Kyle


4 Answers

You could just use a transfer object that implements Serializable, and has the same fields as the third party object. Let the transfer object implement a method that returns an object of the original third party class and you're done:

Pseudocode:

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);
}

You just have to make sure that the members are serialized correctly if you got any special member objects.

Alternatively if the third party class isn't final you could just extend it, have that implement Serializable and write your own writeObject and readObject methods.

Check here for some serialization infos:

  • Serialization Secrets - WayBack
  • Serialization API - Oracle
  • Serialization Secrets - Old
like image 123
fasseg Avatar answered Nov 16 '22 05:11

fasseg


You need to wrap it into something that does the serialization.

Ideally, the third-party class supports some other form of serialization, for example XML serialization (which is based on bean properties). If not, you have to roll your own. Whether that involves reflection or just getters, setters and constructors depends on the class.

In any case, the wrapper would convert the object into a byte[] or a String or something else and write that into the serialization output. On deserialization it reconstructs the object from that data.

The two methods your wrapper has to implement are

private void writeObject(java.io.ObjectOutputStream out)
 throws IOException
private void readObject(java.io.ObjectInputStream in)
 throws IOException, ClassNotFoundException;
like image 37
Thilo Avatar answered Nov 16 '22 06:11

Thilo


A lot depends on the nature of the third party class. Is it final, does it have a no argument constructor, can you construct it given known values or is it constructed by another class, does it itself contain non-Serializable members?

Easiest way is to decompile the class, add an implements Serializable, and recompile it, but if it contains non-Serializable members, things get more complicated.

like image 1
Yishai Avatar answered Nov 16 '22 05:11

Yishai


Another possible solution may be to define a set of private methods inside your Serializable class that uses the instances of the third party class.These special methods are part of a special callback contract the serialization system offers.These methods will be called during the serialization/deserialization process. Their signatures must be like:

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.
}

This example clarifies this idea further:

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;
    }


}

Note that the thirdPartyInstance in MyClass must be declared transient otherwise an exception of type 'java.io.NotSerializableException' occurs. For more explanation see: SCJP Sun Certified Programmer for Java 6 by 'Cathy Sierra',Page Number 497

like image 1
Chandan Kumar Avatar answered Nov 16 '22 05:11

Chandan Kumar