2010-10-01 12 views
61

Estoy implementando una clase para Serializable (por lo que es un objeto de valor para usar con RMI). Pero necesito probarlo. ¿Hay alguna manera de hacer esto fácilmente?cómo probar en Java que una clase implementa Serializable correctamente (no solo es una instancia de Serializable)

aclaración: Estoy implementando la clase, por lo que es trivial incluir Serializable en la definición de la clase. Necesito serializarlo/deserializarlo manualmente para ver si funciona.

He encontrado C# question, ¿hay alguna respuesta similar para Java?

+0

¿Está tratando de probar para ver si el objeto g ¿Están serializados y deserializados adecuadamente? –

+0

sí. (.........) –

Respuesta

100

La manera fácil es comprobar que el objeto es una instancia de java.io.Serializable o java.io.Externalizable, pero eso realmente no prueba que el objeto realmente es serializable.

La única manera de estar seguro es probarlo de verdad. La prueba más simple es algo así como:

new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(myObject); 

y compruebe que no arroja una excepción.

Apache Commons Lang proporciona una versión bastante más breve:

SerializationUtils.serialize(myObject); 

y otra vez, la verificación de la excepción.

Usted puede ser más riguroso aún, y comprobar que deserializa de nuevo en algo igual a la original:

Serializable original = ... 
Serializable copy = SerializationUtils.clone(original); 
assertEquals(original, copy); 

y así sucesivamente.

+0

genial, gracias, esa es la introducción que necesitaba. –

+0

Por si acaso alguien tiene curiosidad o no quiere incluir las bibliotecas de Apache Commons, Spring también tiene SerializationUtils con los métodos 'serialize' y' deserialize'. Ver [SerializationUtils] (http://docs.spring.io/spring/docs/4.1.0.BUILD-SNAPSHOT/javadoc-api/org/springframework/util/SerializationUtils.html) –

+0

Tu respuesta me ayudó, pero 'deserializar() 'y' clone() 'devuelve' Object', no 'Serializable'. – NeplatnyUdaj

2

La respuesta corta es, uno se puede topar con algunos objetos candidatos y en realidad tratar de serializarlos usando el mecanismo de tu elección. La prueba aquí es que no se encuentran errores durante el marshalling/unmarshalling, y que el objeto resultante "rehidratado" es igual al original.

Alternativamente, si no tiene ningún objeto candidato, podría implementar una prueba basada en la reflexión que introspeccione los campos (no estáticos, no transitorios) de su clase para asegurarse de que también sean serializables. Hablando desde la experiencia, esto se vuelve sorprendentemente complejo sorprendentemente rápido, pero se puede hacer en una medida razonable.

La desventaja de este último enfoque es que si un campo es, por ejemplo, List<String>, entonces puede fallar la clase por no tener un campo estrictamente serializable, o simplemente asumir que se utilizará una implementación serializable de List. Ninguno de los dos es perfecto.(Tenga en cuenta que el último problema existe también para ejemplos: si cada ejemplo utilizado en la prueba utiliza listas serializables, no hay nada que impida que una versión no serializable sea utilizada por algún otro código en la práctica).

3

Este código debe hacerlo ... métodos

import java.io.ByteArrayOutputStream; 
import java.io.Externalizable; 
import java.io.IOException; 
import java.io.ObjectOutputStream; 
import java.io.OutputStream; 
import java.io.Serializable; 

public class Main 
{ 
    public static void main(String[] args) 
    { 
     System.out.println(isSerializable("Hello")); 
     System.out.println(isSerializable(new Main())); 
    } 

    public static boolean isSerializable(final Object o) 
    { 
     final boolean retVal; 

     if(implementsInterface(o)) 
     { 
      retVal = attemptToSerialize(o); 
     } 
     else 
     { 
      retVal = false; 
     } 

     return (retVal); 
    } 

    private static boolean implementsInterface(final Object o) 
    { 
     final boolean retVal; 

     retVal = ((o instanceof Serializable) || (o instanceof Externalizable)); 

     return (retVal); 
    } 

    private static boolean attemptToSerialize(final Object o) 
    { 
     final OutputStream sink; 
     ObjectOutputStream stream; 

     stream = null; 

     try 
     { 
      sink = new ByteArrayOutputStream(); 
      stream = new ObjectOutputStream(sink); 
      stream.writeObject(o); 
      // could also re-serilalize at this point too 
     } 
     catch(final IOException ex) 
     { 
      return (false); 
     } 
     finally 
     { 
      if(stream != null) 
      { 
       try 
       { 
        stream.close(); 
       } 
       catch(final IOException ex) 
       { 
        // should not be able to happen 
       } 
      } 
     } 

     return (true); 
    } 
} 
+0

'instanceof Externalizable' implica' instanceof Serializable'. No necesita probar ambos. – EJP

22

de utilidad basado en la respuesta de skaffman:

private static <T extends Serializable> byte[] pickle(T obj) 
     throws IOException 
{ 
    ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
    ObjectOutputStream oos = new ObjectOutputStream(baos); 
    oos.writeObject(obj); 
    oos.close(); 
    return baos.toByteArray(); 
} 

private static <T extends Serializable> T unpickle(byte[] b, Class<T> cl) 
     throws IOException, ClassNotFoundException 
{ 
    ByteArrayInputStream bais = new ByteArrayInputStream(b); 
    ObjectInputStream ois = new ObjectInputStream(bais); 
    Object o = ois.readObject(); 
    return cl.cast(o); 
} 
+0

++ gracias a ti y a skaffman! Estaba buscando algo así para agregar a un arnés de prueba para evitar que los desarrolladores escriban códigos que no sean serializables y que maten a nuestras aplicaciones una vez que lleguen a nuestro servidor agrupado. ¡Un salvavidas! ¡Gracias chicos! –

+0

Más sobre el término "decapado" aquí: https://docs.python.org/2/library/pickle.html – span

1

Esto sólo funciona para los objetos totalmente ocupadas, si necesita que los objetos compuestos en su objeto de nivel superior también son serializables, entonces no pueden ser nulos para que esta prueba sea válida, ya que la serialización/deserialización omite los objetos nulos

Cuestiones relacionadas