cancel
Showing results for 
Search instead for 
Did you mean: 

Classloader trouble while deserializing process variables

danielbehrwind
Champ in-the-making
Champ in-the-making
Hi,

I'm using activiti in a Grails project and having trouble when it comes to deserializing Groovy objects that are stored in process variables. I'm experiencing pretty much the same problems as described in this post (not using the Grails Avticiti plugin, though): http://code.google.com/p/grails-activiti-plugin/issues/detail?id=16
To sum it up, deserializing my objects fails with a ClassNotFoundException, which is due to the wrong ClassLoader being used.

I came up with a workaround employing the suggested solution from http://jira.codehaus.org/browse/GROOVY-1627, which is to subclass ObjectInputStream and overriding the resolveClass method in order to use a specific class loader (in my case the grailsApplication.classLoader). The workaround seems to work but it is rather ugly and I am wondering, if there is a better solution to my problem.

Here's my approach: In order to tap into the process of deserializing process variables, I subclass the Activiti SerializableType and override the getValue method, which is the place where deserialization happens. I basically copy-pasted the SerializableType's implementation an replaced the ObjectInputStream with my custom implementation. During application startup I register my custom SerializableType with the ProcessEngineConfiguration.
Here's my Grails service that does all that:

class CustomSerializableProcessTypeService {

    static transactional = false

    ProcessEngineConfigurationImpl processEngineConfiguration
    def grailsApplication

    void registerCustomSerializableType () {
        processEngineConfiguration.variableTypes.addType (new CustomSerializableType (), 0)
    }

    class CustomSerializableType extends SerializableType {
        @Override
        Object getValue (ValueFields valueFields) {
            Object cachedObject = valueFields.getCachedValue ();
            if (cachedObject != null) {
                return cachedObject;
            }
            byte[] bytes = valueFields.getByteArrayValue ()?.getBytes ();
            ByteArrayInputStream bais = new ByteArrayInputStream (bytes);
            Object deserializedObject = null;
            try {
                ObjectInputStream ois = new CustomObjectInputStream (bais)  // <=== This is the line of interest
                deserializedObject = ois.readObject ();
                valueFields.setCachedValue (deserializedObject);

                if (valueFields instanceof VariableInstanceEntity) {
                    Context.
                          getCommandContext ().
                          getDbSqlSession ().
                          addDeserializedObject (deserializedObject, bytes, (VariableInstanceEntity) valueFields);
                }

            } catch (Exception e) {
                log.warn ("exception occurred in getValue of custom SerializableType, trying super class", e)
            } finally {
                IoUtil.closeSilently (bais);
            }


            if (deserializedObject) {
                return deserializedObject;
            }
            return super.getValue (valueFields)
        }
    }

    class CustomObjectInputStream extends ObjectInputStream {

        CustomObjectInputStream (InputStream inputStream) {
            super(inputStream)
        }

        protected Class resolveClass (ObjectStreamClass objectStreamClass) throws IOException, ClassNotFoundException {
            return Class.forName (objectStreamClass.getName (), true, grailsApplication.classLoader);
        }
    }
}

So here are my questions:

1. Is there a better way fix the ClassLoader issue?

2. If not, is there a better way to register custom VariableTypes? I'm currently using the ProcessEngineConfigurationImpl's VaraibleTypes object, which isn't even exposed by the ProcessEngineConfiguration interface. (By the way, I'm having a hard time to find documentation on this.)

I appreciate any hints!

Thanks a lot
Daniel
1 REPLY 1

trademak
Star Contributor
Star Contributor
Hi,

I think the Grails plugin project would be a better place to raise this question.

Best regards,