groovy

Deserialization fails to work

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Major Major
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None
  • Environment:
    Ubuntu 6.10 Edgy Eft + Groovy r4630
  • Number of attachments :
    0

Description

Serialization appears to work fine but deserialization fails to work at all.

The script;

import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.io.Serializable

class Blah implements Serializable {
  def x
  def y
  public Blah ( x , y ) {
    this.x = x
    this.y = y
  }
}

def fileName = 'thingy.txt'
def data = [ new Blah ( 1 , 2 ) , new Blah ( 'flob' , 'adob' ) ]
def file = new ObjectOutputStream ( new FileOutputStream ( fileName ) )
file.writeObject ( data )
file.close ( )
file = new ObjectInputStream ( new FileInputStream ( fileName ) )
def newData = file.readObject ( ) // ClassNotFoundException here.
assert data == newData

results in the output:

Caught: java.lang.ClassNotFoundException: Blah
at serialization.run(serialization.groovy:22)
at serialization.main(serialization.groovy)

Activity

Hide
blackdrag blackdrag added a comment -

after discussion with several other people I must say it is not the fault of groovy. Java uses the last defined ClassLoader to loader the class. In many environments this might mean that the wrong class loader is chosen or that it works one day and the other day not. The only secure way out of this is the solution I already posted on the mailing list

Show
blackdrag blackdrag added a comment - after discussion with several other people I must say it is not the fault of groovy. Java uses the last defined ClassLoader to loader the class. In many environments this might mean that the wrong class loader is chosen or that it works one day and the other day not. The only secure way out of this is the solution I already posted on the mailing list
Hide
blackdrag blackdrag added a comment -

just to ensure that the solution is known:

DeserializationExample.java
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)) {
   protected Class resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
     return Class.forName(objectStreamClass.getName(), true, myClassLoader);
   }
 };

myClassLoader needs to be a classloader that knows how to resolve he Groovy class we want to deserialize

Show
blackdrag blackdrag added a comment - just to ensure that the solution is known:
DeserializationExample.java
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)) {
   protected Class resolveClass(ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
     return Class.forName(objectStreamClass.getName(), true, myClassLoader);
   }
 };
myClassLoader needs to be a classloader that knows how to resolve he Groovy class we want to deserialize
Hide
Andres Almiray added a comment -

Based on Jochen's latest comment, should this issue be closed or is there something else to be discussed?

Show
Andres Almiray added a comment - Based on Jochen's latest comment, should this issue be closed or is there something else to be discussed?
Hide
Guillaume Laforge added a comment -

We should find a suitable place to document this on the wiki.

Show
Guillaume Laforge added a comment - We should find a suitable place to document this on the wiki.
Hide
Paul King added a comment -

I was planning to add two DGM methods:

public static Object withObjectInputStream(File file, ClassLoader classLoader, Closure closure)
public static ObjectInputStream newObjectInputStream(File file, final ClassLoader classLoader)

They would just codify Jochen's suggested solution above and enable this sort of code:

class Blah implements Serializable {
    def x, y
    boolean equals(def other) { x == other.x && y == other.y }
}

def file = new File('thingy.txt')
def data = [ new Blah(x:1, y:2), new Blah(x:'flob', y:'adob') ]
file.withObjectOutputStream { oos ->
    oos.writeObject ( data )
}
file.withObjectInputStream(getClass().classLoader){ ois ->
    def newData = ois.readObject ( )
    assert data == newData
}

Unless anyone can see an issue with this, I'll add the methods, a test and document on the wiki.

Show
Paul King added a comment - I was planning to add two DGM methods:
public static Object withObjectInputStream(File file, ClassLoader classLoader, Closure closure)
public static ObjectInputStream newObjectInputStream(File file, final ClassLoader classLoader)
They would just codify Jochen's suggested solution above and enable this sort of code:
class Blah implements Serializable {
    def x, y
    boolean equals(def other) { x == other.x && y == other.y }
}

def file = new File('thingy.txt')
def data = [ new Blah(x:1, y:2), new Blah(x:'flob', y:'adob') ]
file.withObjectOutputStream { oos ->
    oos.writeObject ( data )
}
file.withObjectInputStream(getClass().classLoader){ ois ->
    def newData = ois.readObject ( )
    assert data == newData
}
Unless anyone can see an issue with this, I'll add the methods, a test and document on the wiki.
Hide
blackdrag blackdrag added a comment -

hmm... why on file? why not on InputStream?

Show
blackdrag blackdrag added a comment - hmm... why on file? why not on InputStream?
Hide
Paul King added a comment -

We certainly should cover that case as well. I was looking for existing usages and we have never bothered with:

public static ObjectInputStream newObjectInputStream(InputStream inputStream)

becase I guess it would only save one space character. But certainly it would make sense for:

public static ObjectInputStream newObjectInputStream(InputStream inputStream, final ClassLoader classLoader)

Maybe it even makes sense to do the former for consistency.

Show
Paul King added a comment - We certainly should cover that case as well. I was looking for existing usages and we have never bothered with:
public static ObjectInputStream newObjectInputStream(InputStream inputStream)
becase I guess it would only save one space character. But certainly it would make sense for:
public static ObjectInputStream newObjectInputStream(InputStream inputStream, final ClassLoader classLoader)
Maybe it even makes sense to do the former for consistency.
Hide
Paul King added a comment -

The proposed methods added to DGM and test added too.

This doesn't really solve the issue but I was planning to close after documenting on the wiki.

I wonder whether we could eventually provide an AST macro like @AutoClassLoaders (or perhaps a better name) to mimic the behavior Java people might expect. Perhaps it might not be possible in general or may just makes things even more confusing.

Show
Paul King added a comment - The proposed methods added to DGM and test added too. This doesn't really solve the issue but I was planning to close after documenting on the wiki. I wonder whether we could eventually provide an AST macro like @AutoClassLoaders (or perhaps a better name) to mimic the behavior Java people might expect. Perhaps it might not be possible in general or may just makes things even more confusing.
Hide
Luke Daley added a comment - - edited

I have hit this issue, and can't see these methods in the GDK.

What is the status?

(Update: nevermind me, was looking in the wrong place)

Show
Luke Daley added a comment - - edited I have hit this issue, and can't see these methods in the GDK. What is the status? (Update: nevermind me, was looking in the wrong place)
Hide
blackdrag blackdrag added a comment -

still... Paul, can't we close this issue?

Show
blackdrag blackdrag added a comment - still... Paul, can't we close this issue?
Hide
Paul King added a comment -

I guess so as solution is there - still need a wiki update at some point.

Show
Paul King added a comment - I guess so as solution is there - still need a wiki update at some point.
Hide
Paul King added a comment -

Example added to wiki under Streams

Show
Paul King added a comment - Example added to wiki under Streams

People

Vote (0)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: