Hi,
In Camunda cockpit GUI I have a camunda variable with x-java-serialized-object serialisation format and deserialisation does not work in the UI because of the error about unable to load the class.
So for future I will change this to JSON serialisation format. For now, I have 2 questions.
Why use the below kotlin code:
val productDetails: Map<String, String> = mapOf("productName" to "amount")
val objectValue = Variables
.objectValue(productDetails)
.serializationDataFormat(Variables.SerializationDataFormats.JSON)
.create()
execution.setVariable("varName", objectValue)
Why not just do:
execution.setVariable("varName", productDetails)
The Camunda object mapper is already configured so is there a reason to not just set the field directly in camunda variable?
My 2nd question is, now I have a serialised text. Can I somehow manually (using a java code example) deserialise this text into JSON to see its contents? I want to use the string text to get the JSON outside the scope of camunda cockpit or camunda process instance.
You’re running into a common scenario when dealing with Camunda variable serialization. Let’s tackle both of your questions in turn:
1. Why use Variables.objectValue(...).serializationDataFormat(...) instead of setting the value directly?
You’re right that in many cases you can just do:
execution.setVariable("varName", productDetails)
But the explicit approach using Variables.objectValue(...) is used for control and clarity around serialization. Here’s the breakdown:
When to use the explicit Variables.objectValue() form:
You want to explicitly specify the serialization format (e.g., JSON vs. Java Serialized Object).
You want to avoid fallback to default Java serialization, which is what Camunda may use when it doesn’t know how to serialize a complex type.
You’re storing custom classes or complex types, and you want to ensure they’re portable and readable (e.g., for Cockpit, REST API, etc).
Why the direct approach may not always work:
If Camunda doesn’t know how to serialize the object, or can’t infer a format, it may default to application/x-java-serialized-object.
This leads to exactly the kind of issue you’re now trying to avoid: non-human-readable format, class loading issues, etc.
So in summary:
You can use the short version if you’re confident that your object is simple (e.g., Map<String, String>), and that Camunda’s default object mapper is properly configured to serialize it as JSON.
But for robustness and clarity, it’s best to be explicit—especially in a production system or when dealing with process variables that might be viewed in Cockpit or via REST.
2. How to deserialize x-java-serialized-object manually to see its contents in Java?
Yes, you can deserialize it using Java’s ObjectInputStream. Here’s how you can do it manually:
import java.io.*;
import java.util.Map;
public class DeserializeCamundaObject {
public static void main(String[] args) throws Exception {
// This is your serialized base64 string from Camunda
String base64Serialized = "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcAAAAAAAAAABDAAAeHB3BAAAAAB4";
// Decode base64 to bytes
byte[] data = java.util.Base64.getDecoder().decode(base64Serialized);
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) {
Object obj = ois.readObject();
// Now you can cast and inspect it
if (obj instanceof Map) {
Map<?, ?> map = (Map<?, ?>) obj;
System.out.println("Deserialized Map:");
map.forEach((k, v) -> System.out.println(k + " -> " + v));
} else {
System.out.println("Deserialized Object: " + obj);
}
}
}
}
Important Notes:
This only works if the classes involved are present on the classpath. If the object being deserialized references a custom class, that class must be available.
It’s a good idea to move away from this format (as you plan to) and use JSON for better portability and inspection.