Repository navigation
What becomes of a shared value
Your workflow aggregate shares values, and something has to store them. This adapter is the one which cannot tell you what. The Process-Engine-API carries a payload, but it says nothing about how an engine behind it keeps that payload. So the honest answer is shorter here than elsewhere, and it ends with a test you have to run yourself.
Every adapter wiki answers the four questions below, in the same order. So you can put two BPMS side by side: Camunda 7 and Camunda 8.
-
What the platform decided before the BPMS sees anything
Every adapter gets the values already flattened. Which shapes are left after that. -
What this BPMS stores as itself
What the API promises about a payload (nothing), and what the in-memory mock does. -
What your application can say about it
Why there is no property here, and where the answer is instead. -
What it costs to configure nothing
What you cannot learn from this page, and the cheapest way to find it out.
This page is about the way out, from your aggregate to the engine. The way in is what a @TaskParam of your
method reads back. It is described in
What a @TaskParam receives.
When the values are handed over is described in What reaches the engine.
Sharing does not hand your objects to the engine. VanillaBP first flattens what your aggregate exposes. So the
payload this adapter sends is already a map of numbers, texts, booleans, lists and maps. Enums, a UUID and the
java.time values become text. A nested object becomes a map of its own readable attributes. This rule is written
down once, with examples, in What is shared, and when.
That map is the payload of every command this adapter sends. It leaves the adapter exactly as it arrived.
The Process-Engine-API has no variable types. A payload is a Map<String, Object> all the way from the start
command to the delivery of a task. This adapter puts the flattened values into that map and converts nothing. There
is no serialization format to choose, because this API has no format at all.
What happens next is up to the engine, and the API does not describe it. Take an implementation backed by Camunda 7: a value that engine has no variable type for is stored as an object variable, in Camunda 7's own serialization format. An implementation backed by Camunda 8 keeps its variables as JSON in the broker, and a decimal loses its scale there. The wikis of those two adapters describe both cases; the links are at the top of this page. Neither statement is a promise of this adapter.
The in-memory mock which comes with this adapter is the one case with a fixed answer. It keeps the map it was
given and hands back the same objects. So a BigDecimal of 120.50 is still a BigDecimal of 120.50 when a task
is delivered. That makes the mock useful for tests. It is also why a test against the mock proves nothing about the
engine you will run on.
Since VanillaBP 2, the platform checks the TYPE of every value which travels to the BPMS while your application starts. It refuses a value whose type may not arrive as what it was, unless you declared it. The rule and the property are on Which types may travel.
This adapter gives the shortest answer of the three adapters, and it is the honest one. The Process-Engine-API names no engine and no serialization. So a text, a boolean and an enum are known to survive, and for everything else the answer is "cannot say". That never stops a startup. It does cost you a warning, and the way out of the warning is a test against the engine you really run.
The same check has a second half, about the expressions in your models. This is the one adapter which answers it
with nothing. The Process-Engine-API hands over no BPMN model and names no expression language. So the adapter
cannot tell an expression from a literal. It also cannot know which places the engine behind the API evaluates.
Camunda 7 marks an expression with ${...} or #{...}, and Camunda 8 marks one with a leading =. If the adapter
guessed which of the two your engine means, a startup message could say things which are not true. So nothing is
reported and no message appears. accept-expressions-in-the-model works here as everywhere, but it never has
anything to accept. Entry 29 of GAPS.md
says what an engine would have to tell about itself to change this.
Nothing through VanillaBP. There is no property here, because it would have nothing to decide. This adapter has no serializer to configure and no client which it could hand a mapper to.
Where the engine behind the API does need to be told something, tell that engine. You provide its beans yourself
(see Which engine does it talk to?). So whatever it offers for
storing values is configured where you build those beans, not under vanillabp.adapters.<id>.*.
Jackson annotations on a shared class never run, wherever the payload ends up. Take a getter annotated with
@JsonProperty("renamedByJackson"): its value travels under the bean name of the getter. The platform builds the
map from readable properties and never asks Jackson. This is the flattening of the first section, not something an
engine does, so the answer is the same on every BPMS.
It costs you the certainty the other two adapter pages give. The engines behind this API differ in just those places: numbers and nested values. This adapter cannot warn you about a loss it never sees.
So measure it once, against the engine you actually run on, before your models depend on it. Share a decimal whose
scale matters and a whole number larger than a long. Start a workflow, and read back what that engine holds. Add a
nested object if your models navigate one, and look at it the way an operator would. What comes back is the answer
for your setup. Write it down where the next person finds it.
Until then, the advice which holds everywhere holds here too. Share less. A workflow aggregate shares the results a
model decides on and the values an operator reads. An attribute your models never read needs only
@NoSyncWithBPMS, and then it is nobody's problem. And where the digits of a number carry a meaning of their own,
share that value as a String. Every engine stores a String as itself.
