Comment copied from mailing list:
There is something interesting to discuss here. I have an implementation of dehydrate/rehydrate for closures which allows setting null the (owner,delegate,thisObject) and rehydrate a closure by specifying those in a single method.
This works even in case of closures referring another closures, like in this example:
class Controller { def action = { 'Hello' }
def action2 = { action() } }
def ctrl = new Controller()
def a2 = ctrl.action2.dehydrate()
def bos = new ByteArrayOutputStream()
bos.withObjectOutputStream {
it << a2
}
byte[] arr = bos.toByteArray()
def rehyd
new ByteArrayInputStream(arr).withObjectInputStream(this.class.classLoader) {
it.eachObject { o -> rehyd = o }
}
ctrl = new Controller() rehyd = rehyd.rehydrate(ctrl, ctrl, ctrl)
assert rehyd() == 'Hello'
Now, the next example won't work:
class X {}
def x = new X()
def cl = {x}
def dehyd = cl.dehydrate()
def bos = new ByteArrayOutputStream()
bos.withObjectOutputStream {
it << dehyd
}
It will fail because it references an outer variable. Internally, the compiler generates a field for the closure class, referencing class X. This class is not serializable, so the field serialization of the closure will fail. As a workaround, one could write this:
class X {}
def x = new X()
def cl = {x}
def dehyd = cl.dehydrate()
dehyd.@x = null
def bos = new ByteArrayOutputStream()
bos.withObjectOutputStream {
it << dehyd
}
But apart from not being user friendly, it beats the concept of "dehydrate" which is to allow closure serialization. We have several possibilities here:
1. make dehydrate iterate on the closure properties, and if a property is not serializable, nullify it
- rehydrate would then take an optional parameter, a map, which allows setting the "missing" properties after deserialization
- possibly, if a closure has another closure as a field member, we could recursively dehydrate them, but rehydrating would be a little more complex process
2. make dehydrate throw an exception in that case
I don't really like the idea of a method which wants to make things serializable to fail with an exception if a non serializable member is found (why do this with owner, ... then ?). But as I did not have the need for closure serialization like you did, perhaps you could give us your opinion on that ?
Comment copied from mailing list:
There is something interesting to discuss here. I have an implementation of dehydrate/rehydrate for closures which allows setting null the (owner,delegate,thisObject) and rehydrate a closure by specifying those in a single method.
This works even in case of closures referring another closures, like in this example:
class Controller { // not Serializable def action = { 'Hello' } def action2 = { action() } // call to other closure } def ctrl = new Controller() def a2 = ctrl.action2.dehydrate() def bos = new ByteArrayOutputStream() bos.withObjectOutputStream { it << a2 } byte[] arr = bos.toByteArray() def rehyd new ByteArrayInputStream(arr).withObjectInputStream(this.class.classLoader) { it.eachObject { o -> rehyd = o } } ctrl = new Controller() // assert new instance rehyd = rehyd.rehydrate(ctrl, ctrl, ctrl) assert rehyd() == 'Hello'Now, the next example won't work:
class X {} def x = new X() def cl = {x} def dehyd = cl.dehydrate() def bos = new ByteArrayOutputStream() bos.withObjectOutputStream { it << dehyd }It will fail because it references an outer variable. Internally, the compiler generates a field for the closure class, referencing class X. This class is not serializable, so the field serialization of the closure will fail. As a workaround, one could write this:
class X {} def x = new X() def cl = {x} def dehyd = cl.dehydrate() dehyd.@x = null def bos = new ByteArrayOutputStream() bos.withObjectOutputStream { it << dehyd }But apart from not being user friendly, it beats the concept of "dehydrate" which is to allow closure serialization. We have several possibilities here:
1. make dehydrate iterate on the closure properties, and if a property is not serializable, nullify it
2. make dehydrate throw an exception in that case
I don't really like the idea of a method which wants to make things serializable to fail with an exception if a non serializable member is found (why do this with owner, ... then ?). But as I did not have the need for closure serialization like you did, perhaps you could give us your opinion on that ?