Tuesday, April 30, 2013

Reading Groovy objects from Java

Loading a Groovy object in Java is not as easy at it seems, but doesn't have to be hard.

The problem with Groovy dynamic classes is that the default class loader is not aware of them. Using the GroovyClassLoader should be as simple as:
GroovyClassLoader gcl = new GroovyClassLoader(); 
Thread.currentThread().setContextClassLoader(gcl); 

Doesn't do the trick and a call to the ObjectInputStream will raise the devil's ClassNotFoundException.

After many attempts refining my Google search from "reading Groovy objects" down to "ObjectInputStream ClassLoader" I finally found this link and was able to solve the problem.
The trick was overriding the resolveClass method from the ObjectInputStream, which apparently always uses the default class loader.

Full code example below.

TestObjectInputStream.java:
public class TestObjectInputStream extends ObjectInputStream { 

    @Override 
    public Class resolveClass(ObjectStreamClass desc) throws IOException,
            ClassNotFoundException { 

        ClassLoader currentTccl = null
        try { 
            currentTccl = Thread.currentThread().getContextClassLoader();
            return currentTccl.loadClass(desc.getName()); 

        } catch (Exception e) { 
        } 

        return super.resolveClass(desc); 
    } 

    public TestObjectInputStream(InputStream in) throws IOException { 
        super(in); 
    } 

}

TestSave.java:
public class TestSave { 
   public static void main(String[] args) throws CompilationFailedException, 
            IOException, InstantiationException, IllegalAccessException, 
            ClassNotFoundException, IllegalArgumentException, 
            SecurityException, InvocationTargetException, NoSuchMethodException { 
        GroovyClassLoader gcl = new GroovyClassLoader(); 
        Thread.currentThread().setContextClassLoader(gcl); 
                                                             
        String fileName = "scripts/SimpleData.groovy"
     
        Class clazz = gcl.parseClass(new File(fileName)); 

         
        Object instance = clazz.newInstance(); 

        System.out.println("WRITING OBJECT FROM CLASS: " + instance.getClass());

        // write 
        File outFile = new File("file.bin"); 
        FileOutputStream fos = new FileOutputStream(outFile); 
        ObjectOutputStream oos = new ObjectOutputStream(fos); 
        oos.writeObject(instance); 

        // read 
        File inFile = new File("file.bin"); 
        FileInputStream fis = new FileInputStream(inFile); 
        TestObjectInputStream ois = new TestObjectInputStream(fis); 

        Object obj = ois.readObject(); 

        System.out.println("Class: " + obj.getClass()); 

        System.out.println("Object: " + obj.toString()); 
        System.out.println("Object: " + obj.toString()); 
        System.out.println("Object: " + obj.toString()); 

        Serializable seriobj = (Serializable) obj; 

        System.out.println("Serializable Object: " + seriobj); 
    } 
SimpleData.groovy:
class SimpleData implements Serializable { 
    public int value = 1; 

    public SimpleData(){ 
    } 

    public String toString(){ 
        return "Value: " + (value ++); 
    } 

And the console's output:
WRITING OBJECT FROM CLASS: class SimpleData
Class: class SimpleData
Object: Value: 1
Object: Value: 2
Object: Value: 3
Serializable Object: Value: 4




No comments:

Post a Comment