cancel
Showing results for 
Search instead for 
Did you mean: 

Variable serialization & Class Loading

oefimov
Champ in-the-making
Champ in-the-making
AFAIK Activiti Engine offers class loading extension point by the following means:
  • Developer can provide custom class loader by setting
    classLoader
    property of
    org.activiti.engine.ProcessEngineConfiguration
    ;
  • Custom class loader may refer to the
    org.activiti.engine.impl.context.Context.getExecutionContext().getProcessDefinition().getDeploymentId()
    method for deployment context.
However, if you want to use variables in you process instance of types defined in the per-deployment class loader, you'll find yourself in trouble: Activiti Engine will call your class loader without providing context information.

This can be seen in class
org.activiti.engine.impl.variable.SerializableType
:

  protected ObjectInputStream createObjectInputStream(InputStream is) throws IOException {
    return new ObjectInputStream(is) {
      protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        return ReflectUtil.loadClass(desc.getName());
      }
    };
  }

No context information is set here before loading the class.

Even if core team decides to abandon this request, I would like to extend core behaviour with providing deployment context  in se/deserialization.

However, overriding this behaviour is cumbersome since classes
org.activiti.engine.impl.variable.SerializableType
and
org.activiti.engine.impl.variable.DeserializedObject
are rather poorly designed:
  • it's hard to override
    org.activiti.engine.impl.variable.SerializableType.createObjectOutputStream
    , since it's private static – you have to copy/paste entire methods calling it. Its fellow method createObjectInputStream is protected and not static.
  • org.activiti.engine.impl.variable.DeserializedObject.flush()
    uses static method mentioned above, you have to overrride the entire method and also override methods containing creation of deserialized object in
    org.activiti.engine.impl.variable.SerializableType
    . I would suggest deserialized object calling callback method for serialization in the creating object, which is subject to overriding.
4 REPLIES 4

jbarrez
Star Contributor
Star Contributor
So you mean you want to have classloaders specifically for certain deployments?
The problem is that this information is not always available and sometimes will need to be fetched from the database, right?

Regarding your suggestions of code changes: it's easier to put these into pull requests where we can discuss them and incorporate them in the code if both parties agree. Would you be able to do that?

oefimov
Champ in-the-making
Champ in-the-making
Joram, yes, if variable is of per-deployment class then during its deserialization the quick way to learn its classloader is via serialized information.

Another solution is to set context above in the call stack, wrapping deserialization invocations (engine knows for which process>definition>deployment it is deserializing a variable), but it's hard for me to assess impact and feasibility of such solution.

I'll make a pull request for the first variant and post link to it here, okay?

oefimov
Champ in-the-making
Champ in-the-making
Hi Joram,

Please review the pull request I've created: https://github.com/Activiti/Activiti/pull/360

jbarrez
Star Contributor
Star Contributor
Certainly. We will reviewing pull requests shortly, it's very hectic currently (just before the Alfresco Summit it is always crazy)