В java, как я сериализую класс, который не помечен Serializable?

В сторонней библиотеке есть определенный класс, который я хочу сериализовать. Как мне это сделать?

Я предполагаю, что мне придется написать метод, который принимает объект класса и использует отражение, чтобы получить значения частного члена. Тогда для десериализации я бы использовал отражение, чтобы вернуть значения.

Будет ли это работать? Есть ли более простой способ?

Ответ 1

Вы можете просто использовать объект передачи, который реализует Serializable, и имеет те же поля, что и сторонний объект. Пусть объект передачи реализует метод, возвращающий объект исходного класса третьей стороны, и вы закончили:

псевдокод:

class Thirdparty{

    int field1;
    int field;
}

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

Вам просто нужно убедиться, что члены сериализованы правильно, если у вас есть специальные объекты-члены.

Альтернативно, если сторонний класс не является окончательным, вы можете просто расширить его, иметь реализацию Serializable и написать свои собственные методы writeObject и readObject.

Проверьте здесь информацию о сериализации:

Секреты сериализации

Ответ 2

Вам нужно обернуть его во что-то, что делает сериализацию.

В идеале сторонний класс поддерживает некоторую другую сериализацию, например, сериализацию XML (которая основана на свойствах bean). Если нет, вам нужно сворачивать самостоятельно. Включает ли это отражение или просто геттеры, сеттеры и конструкторы зависит от класса.

В любом случае оболочка преобразует объект в байт [] или строку или что-то еще и записывает это в вывод сериализации. При десериализации он восстанавливает объект из этих данных.

Два метода, которые должна выполнить ваша обертка, - это

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

Ответ 3

Многое зависит от характера третьего класса. Является ли это окончательным, имеет ли он конструктор без аргументов, вы можете его построить с помощью известных значений или он построен другим классом, сам ли он содержит несериализуемые элементы?

Самый простой способ - декомпилировать класс, добавить средство Serializable и перекомпилировать его, но если он содержит несериализуемые члены, все становится сложнее.

Ответ 4

Другим возможным решением может быть определение набора частных методов внутри вашего класса 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;
    }


}

Обратите внимание, что thirdPartyInstance в MyClass должен быть объявлен переходным процессом, иначе произойдет исключение типа "java.io.NotSerializableException". Для получения дополнительной информации см.: SCJP Sun Certified Programmer для Java 6 от "Cathy Sierra", номер страницы 497