2008-09-18 12 views
51

tengo:serialización de Java con partes no serializables

class MyClass extends MyClass2 implements Serializable { 
    //... 
} 

En miclase2 es una propiedad que no es serializable. ¿Cómo puedo serializar (y deserializar) este objeto?

Corrección: miclase2 es, por supuesto, no es una interfaz, pero una clase.

+0

¿Se puede modificar miclase2 o no? ¿El valor de propiedad no serializable debe conservarse por serialización? El enfoque correcto depende de esto. – erickson

+0

MyClass2 podría ser modificado. Sin embargo, sería mejor no hacerlo, ya que construyo sobre él y puede ser modificado por otros. – Burkhard

Respuesta

49

Como alguien más ha dicho, el capítulo 11 de Josh Bloch Effective Java es un recurso indispensable en Java La serialización.

un par de puntos de ese capítulo pertinente a su pregunta:

  • asumiendo que usted quiere para serializar el estado del campo no serializable en miclase2, este campo debe ser accesible a MiClase, ya sea directamente o por medio de captadores y setters. MyClass tendrá que implementar una serialización personalizada al proporcionar los métodos readObject y writeObject.
  • la clase del campo no serializable debe tener una API que permita obtener su estado (para escribir en la secuencia del objeto) y luego instanciar una nueva instancia con ese estado (cuando lea posteriormente la secuencia del objeto)
  • por artículo 74 de Effective Java, MyClass2 debe tener tener un constructor no-arg accesible para MyClass, de lo contrario es imposible que MyClass extienda MyClass2 e implemente Serializable.

He escrito un ejemplo rápido a continuación para ilustrar esto.


class MyClass extends MyClass2 implements Serializable{ 

    public MyClass(int quantity) { 
    setNonSerializableProperty(new NonSerializableClass(quantity)); 
    } 

    private void writeObject(java.io.ObjectOutputStream out) 
    throws IOException{ 
    // note, here we don't need out.defaultWriteObject(); because 
    // MyClass has no other state to serialize 
    out.writeInt(super.getNonSerializableProperty().getQuantity()); 
    } 

    private void readObject(java.io.ObjectInputStream in) 
    throws IOException { 
    // note, here we don't need in.defaultReadObject(); 
    // because MyClass has no other state to deserialize 
    super.setNonSerializableProperty(new NonSerializableClass(in.readInt())); 
    } 
} 

/* this class must have no-arg constructor accessible to MyClass */ 
class MyClass2 { 

    /* this property must be gettable/settable by MyClass. It cannot be final, therefore. */ 
    private NonSerializableClass nonSerializableProperty; 

    public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) { 
    this.nonSerializableProperty = nonSerializableProperty; 
    } 

    public NonSerializableClass getNonSerializableProperty() { 
    return nonSerializableProperty; 
    } 
} 

class NonSerializableClass{ 

    private final int quantity; 

    public NonSerializableClass(int quantity){ 
    this.quantity = quantity; 
    } 

    public int getQuantity() { 
    return quantity; 
    } 
} 
+6

Aww Esperaba algún tipo de de anotación como @NonSerialization: - / –

33

miclase2 es sólo una interfaz para techinicaly no tiene propiedades, únicos métodos. Dicho esto, si tiene variables de instancia que no son serializables, la única forma que conozco de evitarlo es declarar esos campos transitorios.

ejemplo:

private transient Foo foo; 

Cuando se declara un transitorio campo será ignorado durante el proceso de serialización y deserialización. Tenga en cuenta que cuando deserialice un objeto con un campo transitorio, el valor de ese campo siempre será el predeterminado (generalmente nulo).

Tenga en cuenta que también puede anular el método readResolve() de su clase para inicializar campos transitorios basados en otro estado del sistema.

6

Deberá implementar writeObject() y readObject() y hacer la serialización/deserialización manual de esos campos. Vea la página de javadoc para java.io.Serializable para más detalles. El de Josh Bloch Effective Java también tiene algunos buenos capítulos sobre la implementación de la serialización robusta y segura.

4

Puede comenzar por buscar palabra clave transitoria, que marca los campos como no parte del estado persistente de un objeto.

11

Si se puede modificar miclase2, la forma más fácil para hacer frente a esto es declarar el transitorio propiedad.

+0

Esto no responde la pregunta: la pregunta indica que MyClass2 contiene la propiedad que no es serializable, e idealmente MyClass2 no debería modificarse. –

+0

Tienes razón, no leí la pregunta con mucho cuidado cuando respondí. Modifiqué la respuesta. – ykaganovich

3

XStream es una gran biblioteca de Java para hacer rápido para la serialización XML para cualquier objeto, sin importar si es o no Serializable. Incluso si el formato de destino XML no le conviene, puede usar el código fuente para aprender cómo hacerlo.

+0

hola, ¿podría explicarme cómo usar XStream con un objeto no serializable? – SWAppDev

+0

La documentación es muy autoexplicativa, el tutorial comienza con clases que no implementan Serializable y le muestra cómo serializarlas: http://x-stream.github.io/tutorial.html –

5

Depende de por qué ese miembro de MyClass2 no es serializable.

Si hay alguna buena razón por la cual MyClass2 no se puede representar en forma serializada, entonces es probable que la misma razón se aplique a MyClass, ya que es una subclase.

Puede ser posible escribir un formulario serializado personalizado para MyClass implementando readObject y writeObject, de tal manera que el estado de los datos de instancia de MyClass2 en MyClass pueda recrearse adecuadamente a partir de los datos serializados. Este sería el camino a seguir si la API de MyClass2 está arreglada y no puede agregar Serializable.

Pero primero debe averiguar qué miclase2 no es serializable, y tal vez cambie.

2

Un enfoque útil para serialising instancias de clases no serializables (o al menos subclases de) se conoce un Proxy de serie. Esencialmente implementamos writeReplace para devolver una instancia de una clase serializable completamente diferente que implementa readResolve para devolver una copia del objeto original. Escribí un ejemplo de serialising java.awt.BasicStroke en Usenet

4

Varias posibilidades poped a cabo y les reanudar aquí:

  • Implementar writeObject() y readObject() como sk sugirió
  • declaran la propiedad transitoria y no va a ser serializado como primera declarado por hank
  • uso xstream según lo declarado por boris-terzic
  • utilizar un proxy de serie según lo declarado por tom-hawtin-tackline
15

Si es posible, las partes no serialiable se puede configurar como transitorio

private transient SomeClass myClz; 

contrario, puede utilizar Kryo. Kryo es un marco de serialización de gráficos de objetos rápido y eficiente para Java (por ejemplo, la serialización JAVA de java.awt.Color requiere 170 bytes, Kryo solo 4 bytes), que también puede serializar objetos no serializables. Kryo también puede realizar copias/clonaciones profundas y superficiales automáticas. Esto es copia directa de un objeto a otro, no object->bytes->object.

Aquí hay un ejemplo de cómo utilizar Kryo

Kryo kryo = new Kryo(); 
// #### Store to disk... 
Output output = new Output(new FileOutputStream("file.bin")); 
SomeClass someObject = ... 
kryo.writeObject(output, someObject); 
output.close(); 
// ### Restore from disk... 
Input input = new Input(new FileInputStream("file.bin")); 
SomeClass someObject = kryo.readObject(input, SomeClass.class); 
input.close(); 

objetos serializados También se puede comprimir mediante el registro serializador exacta:

kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class))); 
Cuestiones relacionadas