java serialization lambda java-8

java - Incapaz de deserializar lambda



serialization java-8 (2)

Solo como un pequeño proyecto, he estado tratando de hacer algo pequeño que lea lambdas serializadas (localmente o desde un FTP) e invoque sus funciones de ejecución como parte de una prueba para experimentar con asociaciones de archivos en Windows (es decir, abrir ciertos tipos de archivos los abre con un cierto programa) y otras cosas, pero no importa lo que intente, nunca parece deserializarse correctamente.

La lambda fue declarada así

Runnable r = (Runnable & Serializable) () -> { // blah blah // made sure not to capture anything };

y serializado usando un FileOutputStream envuelto por un [n opcional] BufferedOutputStream envuelto por un ObjectOutputStream sin problema. Sin embargo, cuando se deserializa [en un proyecto diferente], falla, diciendo que no pudo encontrar la clase que contenía el código para serializarlo. He intentado varias cosas como envolverlos en una clase serializable (w / serialVersionUID = 0L para fines de prueba) o definir una interfaz que extienda Runnable y Serializable, pero fue en vano.

Sí, soy consciente de que serializar lambdas no es realmente una buena práctica (o eso nos dicen), pero no estoy seguro de cómo convertir las funciones y subrutinas en algo que pueda almacenar como un archivo o en un FTP. Si esta no es la forma correcta, dilo.

Oh, estoy usando Eclipse Luna de cualquiera que sea la última versión.

Editar:

Deserializado así

File f = new File(somePath); FileInputStream fish = new FileInputStream(f); BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary ObjectInputStream ois = new ObjectInputStream(bos); Runnable r = (Runnable) ois.readObject(); ois.close(); r.run();


Cuando deserializa un objeto, el código que realiza la deserialización debe conocer la clase del objeto serializado. No puede serializar una lambda arbitraria y deserializarla en otra base de código.

Más o menos, el código de serialización y deserialización debe estar en la misma base de código, o al menos debe compartir una dependencia del código que contiene el lambda original.


No puede deserializar un objeto sin que la clase lo defina. Esto no ha cambiado con las expresiones lambda.

Las expresiones lambda son un poco más complejas, ya que su clase de tiempo de ejecución generada no es la clase que la definió, pero su clase definitoria es la que contiene el código del cuerpo de la lambda y, en el caso de lambdas serializables, un método de soporte de deserialización que se llama para validar y volver a instanciar la instancia lambda.

Ver SerializedLambda :

Se espera que los implementadores de lambdas serializables, como compiladores o bibliotecas de tiempo de ejecución de lenguaje, se aseguren de que las instancias se deserialicen correctamente. Una forma de hacerlo es asegurarse de que el método writeReplace devuelva una instancia de SerializedLambda , en lugar de permitir que continúe la serialización predeterminada.

SerializedLambda tiene un método readResolve que busca un método estático (posiblemente privado) llamado $deserializeLambda$(SerializedLambda) en la clase de captura, lo invoca a sí mismo como primer argumento y devuelve el resultado. Las clases Lambda que implementan $deserializeLambda$ son responsables de validar que las propiedades de SerializedLambda son consistentes con una lambda realmente capturada por esa clase.

Entonces, incluso si su instancia no se refería a un método sintético dentro de la clase definitoria (por ejemplo, en el caso de una referencia de método a un método fuera de esta clase), la deserialización aún requiere $deserializeLambda$ para validar la corrección de la instancia, intencionalmente.

Con respecto a la "buena práctica" de serializar lambdas, tenga en cuenta que las expresiones lambda encapsulan el comportamiento , no el estado. Almacenar el comportamiento siempre implica almacenar solo algún tipo de referencia y requerir que el código destinado a restaurarlo, haya implementado el comportamiento asociado. Eso funcionaría también si solo se refiriera al comportamiento previsto mediante un nombre simbólico o simplemente almacenado, por ejemplo, valores de enum asociados.

En esta pregunta se explica más sobre las implicaciones de tener lambdas serializables.