2010-01-22 14 views
11

Hay una clase específica en una biblioteca de terceros que deseo serializar. ¿Cómo voy a hacer esto?En Java, ¿cómo serializo una clase que no está marcada como Serializable?

Supongo que tendré que escribir un método que tome un objeto de la clase y use la reflexión para obtener los valores de miembros privados. Luego, para la deserialización, utilizaría la reflexión para devolver los valores.

¿Funcionaría? hay una manera mas facil?

+0

¿lo necesita para ser compatible con versiones futuras? –

+0

No, no necesita ser compatible con versiones futuras. – Kyle

+0

¿Solo quieres persistir en los datos? Si es así, ¿por qué no usar JAXB? – Boltimuss

Respuesta

12

Puede utilizar simplemente un objeto de transferencia que implementa Serializable y tiene los mismos campos que el objeto de terceros. Deje que el objeto de transferencia implementar un método que devuelve un objeto de la clase original terceros y ya está:

pseudocódigo:

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

Sólo hay que asegurarse de que los miembros se serializan correctamente si tiene cualquier objeto miembro especial.

Alternativamente, si la clase de terceros no es definitiva, puede ampliarla, hacer que implemente Serializable y escribir sus propios métodos writeObject y readObject.

Marque aquí para algunas informaciones de serialización:

Serialization Secrets

+0

Gracias, esto parece bueno, ¿qué hago con las variables de miembros privados? ¿Hay una manera fácil de hacerlo o necesito reflexión? – Kyle

+0

yep reflection es la única forma que conozco para acceder a campos no visibles. : / – fasseg

2

Usted necesita envolverlo en algo que hace la serialización.

Idealmente, la clase de terceros admite alguna otra forma de serialización, por ejemplo, la serialización XML (que se basa en propiedades de bean). Si no, debes tirar el tuyo. Ya sea que eso implique reflexión o solo getters, setters y constructores depende de la clase.

En cualquier caso, el contenedor convertiría el objeto en un byte [] o un String o algo más y lo escribiría en la salida de serialización. En la deserialización, reconstruye el objeto a partir de esos datos.

Los dos métodos de su envoltorio tiene que aplicar son

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

Mucho depende de la naturaleza de la tercera clase del partido. ¿Es final, tiene un constructor sin argumentos, puede construirse con valores conocidos o está construido por otra clase, contiene miembros no serializables?

La manera más fácil es descompilar la clase, agregar un implementable Serializable y volver a compilarlo, pero si contiene miembros no serializables, las cosas se vuelven más complicadas.

0

Otra posible solución puede ser definir un conjunto de métodos privados dentro de su clase Serializable que utiliza las instancias de la clase de terceros. Estos métodos especiales son parte de un contrato de devolución de llamada especial que ofrece el sistema de serialización. durante el proceso de serialización/deserialización. Sus firmas deben ser como:

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

Este ejemplo aclara esta idea:

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


} 

Tenga en cuenta que la thirdPartyInstance en MiClase debe ser declarado transitoria de otro modo una excepción del tipo 'java.io.NotSerializableException' ocurre. Para obtener más información, consulte: SCJP Programador certificado para Java 6 por "Cathy Sierra", número de página 497

Cuestiones relacionadas