В Java, как мне сериализовать класс, который не помечен как Serializable? - PullRequest
12 голосов
/ 22 января 2010

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

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

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

Ответы [ 4 ]

13 голосов
/ 22 января 2010

Вы можете просто использовать объект переноса, который реализует 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);
}

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

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

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

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

2 голосов
/ 22 января 2010

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

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

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

Два метода, которые должен использовать ваш упаковщик:

private void writeObject(java.io.ObjectOutputStream out)
 throws IOException
private void readObject(java.io.ObjectInputStream in)
 throws IOException, ClassNotFoundException;
1 голос
/ 24 июля 2015

Другим возможным решением может быть определение набора частных методов внутри вашего класса 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 сертифицированный программист для Java 6 от Cathy Sierra, номер страницы 497

1 голос
/ 22 января 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...