Skip to main content
Skip table of contents

Workflow expressies syntax

Concept

Workflow expressies worden geschreven in JUEL (Java Unified Expression Language), een implementatie van de Jakarta Expression Language. Camunda 7 gebruikt JUEL als expressietaal in BPMN-processen en voegt er eigen variabelen en services aan toe.

Een expressie is pas uitvoerbaar als die tussen accolades genoteerd staat. Het geheel wordt door een $ dollarteken voorafgegaan.

${expressie}

Via method chaining kan je meerdere elementen in een logisch verband onderbrengen.

${voornaam.concat(' ‘).concat(achternaam)}

Expressies bieden slechts beperkte functionaliteit. Heb je nood aan meer complexiteit (bijvoorbeeld itereren over lijstelementen)? Dan kan je gebruik maken van scripts.

Wil je een apart stukje code opstellen en deze vervolgens oproepen via een workflow expressie? Kijk dan onder de sectie extensies en customizaties.

Data types

Primitieve waardes

Volgende primitieve data types zijn ondersteund binnen workflow expressies.

Data type

Voorbeeld waarde

Null

Geen waarde

String

'Hello World!'

Boolean

true or false

Integer

15 (geheel getal, negatief of positief)

Double

15.5 (decimaal getal, negatief of positief)

Datum

2025-04-01T13:49:13 (altijd inclusief tijdsstempel)

Opmerkingen:

  • Een datum literal kan je niet rechtstreeks noteren in een expressie. Gebruik een van de datum-functies hieronder.

  • De tabel toont de meest gebruikte types. Java kent ook Long, Float en andere numerieke types, maar die komen in de praktijk zelden voor binnen Skryv-configuraties.

Data objecten

Naast primitieve waarden kunnen procesvariabelen ook complexe datastructuren bevatten.

Data structuur

Voorbeeld opbouw

Lijst

['value1','value2','value3']

Map

{“key1”:'value1',“key2”:'value2',“key3”:'value3'}

Lijst-Map

[{“key1”:'value1',“key2”:'value2',“key3”:'value3'},{“key1”:'value1',“key2”:'value2',“key3”:'value3'},{“key1”:'value1',“key2”:'value2',“key3”:'value3'}]

Omgaan met data objecten

Procesvariabelen met een complexere structuur zoals lijsten, maps en lijst-maps kan je op volgende manieren manipuleren vanuit een expressie. De mogelijkheden zijn erg beperkt. Via een workflow script kan je extra zaken doen zoals bijvoorbeeld waardes toevoegen aan of verwijderen uit een lijst.

Waarde ophalen

Je kan een waarde ophalen via volgende expressie.

${mijnVariabele} retourneert de waarde van de procesvariabele mijnVariabele.

Waarde uit een lijst ophalen

Je kan een waarde uit een lijst ophalen via de index.

${mijnLijst[0]} retourneert het eerste item in de lijst.

Aantal items in een lijst vaststellen

Lengte van een lijst vaststellen.

mijnLijst = ['jan','mieke','paul']

${mijnLijst.size()} retourneert het aantal items in de lijst als integer (bijvoorbeeld 3).

Waarde uit een map ophalen

Je kan een waarde uit een map ophalen via de key.

${mijnMap['leeftijd']} retourneert de waarde van de key ‘leeftijd’ in de map.

Waarde uit een lijst-map ophalen

Je kan een waarde uit een lijst-map ophalen via combinatie van index en key.

${mijnLijstMap[0]['leeftijd']} retourneert de waarde van de key ‘leeftijd’ uit het eerste item in de lijst-map.

Operatoren

Booleaanse operatoren

Operator

Beschrijving

Data types

&&

Verbindt twee booleaanse waardes. Indien de twee waardes true zijn, dan retourneert de expressie true. Vanaf het ogenblik dat één van beide waardes (of allebei) false is, dan retourneert de expressie false.

Tekstueel equivalent: and

Boolean

||

Verbindt twee booleaanse waardes. Vanaf het ogenblik dat één van beide waardes (of allebei) true is, dan retourneert de expressie true. Indien beide waardes false zijn, dan retourneert de expressie false.

Tekstueel equivalent: or

Boolean

!

Negeert een booleaanse waarde. !true retourneert false.

Tekstueel equivalent: not().

Boolean

empty

Retourneert true als de waarde null, een lege string '', een lege lijst [] of een lege map {} is.

Boolean

Vergelijkende operatoren

Operator

Beschrijving

Data types

==

Vergelijk twee waardes met elkaar. Indien identiek, retourneert de expressie true. Indien niet, retourneert de expressie false. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: eq

String, boolean, number, date

!=

Vergelijk twee waardes met elkaar. Indien identiek, retourneert de expressie false. Indien niet, retourneert de expressie true. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: ne

String, boolean, number, date

<

Vergelijkt twee waardes met elkaar. Indien waarde A kleiner dan waarde B, retourneert de expressie true. Indien waarde A gelijk of groter dan waarde B, retourneert de expressie false. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: lt

Number, date

>

Vergelijkt twee waardes met elkaar. Indien waarde A groter dan waarde B, retourneert de expressie true. Indien waarde A gelijk of kleiner dan waarde B, retourneert de expressie false. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: gt

Number, date

<=

Vergelijkt twee waardes met elkaar. Indien waarde A kleiner of gelijk aan waarde B, retourneert de expressie true. Indien waarde A groter dan waarde B, retourneert de expressie false. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: le

Number, date

>=

Vergelijkt twee waardes met elkaar. Indien waarde A groter of gelijk aan waarde B, retourneert de expressie true. Indien waarde A kleiner dan waarde B, retourneert de expressie false. De vergeleken waardes moeten van hetzelfde data type zijn.

Tekstueel equivalent: ge

Number, date

Opmerking: in XML-contexten (zoals BPMN-bestanden) is het soms beter de tekstuele alternatieven gebruiken: and, or, eq, ne, lt, gt, le, ge — om te vermijden dat symbolen zoals < of & geëscaped moeten worden.

Empty check of null-check

Controleer of een procesvariabele een waarde heeft:

CODE
${mijnVariabele != null}    // true als de variabele een waarde heeft
${mijnVariabele == null}    // true als de variabele geen waarde heeft

Voor strings kan je ook empty gebruiken, dat zowel null als lege strings opvangt:

${not empty mijnVariabele}

Logische statements

Statement

Beschrijving

[boolean] ? [functie A] : [functie B]

Indien boolean true is, voer functie A uit. Indien boolean false is, voer functie B uit. Je kan dergelijke statements bouwen via de workflow expression builder.

Functies

Camunda engine services

Functies worden aaneengeregen tot expressies via de Fluent API methodiek (method chaining). Meer details voor courant gebruikte Camunda engine services.

Skryv platform services

Functies worden aaneengeregen tot expressies via de Fluent API methodiek (method chaining). Meer details voor courant gebruikte Skryv platform services.

Datum tijd functies

Datum en tijd ophalen

Hiervoor heb je twee mogelijke expressies:

  • ${now()}

  • ${dateTime().toDate()}

Deze resulteren in een java.util.Date-object met datum waarde als 2025-04-01T13:49:13.

Datum en tijd instellen

Ook hiervoor heb je verschillende mogelijkheden. Onderstaande is er één van.

${dateTime().withDate(2030,12,30).toDate()}

Het resultaat is een datum waarde 2030-12-30T09:24:30, waarbij de tijdsstempel gelijk is aan het ogenblik waarop de variabele aangemaakt wordt.

Wil je ook de tijdsstempel preciseren, dan voeg je .withTime() method toe.

${dateTime().withDate(2030,12,30).withTime(12,0,0,0).toDate()}

Opgelet, de workflow engine zit in tijdszone UTC, en een tijdsstempel zetten is dus vanuit UTC tijd gezien. Doordat België zich in de winter in UTC+1 bevindt, zal de resulterende datum waarde 2030-12-30T13:00:00 zijn. In de zomer bevindt België zich in UTC+2, dus zal de resulterende datum waarde bijvoorbeeld 2030-06-30T14:00:00 zijn.

Datum en tijd componenten ophalen

Functie met voorbeeld

Beschrijving

${dateTime(mijnDatum).year}

Retourneert het jaar als integer.

${dateTime(mijnDatum).monthOfYear}

Retourneert de maand als integer.

${dateTime(mijnDatum).dayOfMonth}

Retourneert de dag als integer.

${dateTime(mijnDatum).hourOfDay}

Retourneert het uur als integer.

${dateTime(mijnDatum).dayOfWeek}

Retourneert de dag van de week als integer (1=maandag, 7=zondag).

Opgelet: hiervoor moet mijnDatum van het type datum zijn, niet van het type string. Gebruik indien nodig eerst dateTime().parse(mijnDatum) om te converteren.

Datumveld uit formulier omzetten naar een datum waarde

Dit kan je doen in twee stappen:

  • Stap 1: Breng de waarde van het datumveld formulier over naar een procesvariabele zoals mijnDatum. De waarde is nu evenwel van het type string.

  • Stap 2: Zet daarom nu de procesvariabele om naar een datum waarde via volgende expressie ${dateTime().parse(mijnDatum).toDate()}

Het resultaat is een datum waarde, bijvoorbeeld: 2025-04-01T00:00:00

Datumwaarde wegschrijven naar een datumveld in formulier

Een procesvariabele (bijvoorbeeld ‘test’) met een datum waarde kan je via de setField functie in het formulierveld (bijvoorbeeld ‘datum’) wegschrijven.

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("testFormulierC").setField("datum",test)}

De tijdsstempel wordt achterwege gelaten en de datum wordt geformatteerd als string-waarde.

Rekenen met datum tijd binnen workflow

Binnen de scope van de workflow is het best practice om timer events te gebruiken. Enkele voorbeelden van use cases: na weigering krijgt de aanvrager nog 30 dagen de mogelijkheid om beroep aan te tekenen, twee dagen vóór de opleveringsdatum van een taak wordt een reminder uitgestuurd naar de uitvoerder van de taak, enzovoort. Klik hier voor meer uitleg over timer events, hun gedrag en eigenschappen.

Rekenen met datum tijd binnen expressies

Binnen de scope van een expressie kan je volgende functies aanspreken.

Functie met voorbeeld

Beschrijving

${dateTime().plusDays(1).toDate()}

Zelfde opbouw lukt ook met plusYears(), plusMonths(), plusWeeks(), plusHours(), plusMinutes(), plusSeconds(). Je kan ook combinaties maken.

Retourneert de huidige datum plus één dag.

${dateTime().minusDays(1).toDate()}

Zelfde opbouw lukt ook met minusYears(), minusMonths(), minusWeeks(), minusHours(), minusMinutes(), minusSeconds(). Je kan ook combinaties maken.

Retourneert de huidige datum min één dag.

${datum1 > datum2}

Alternatief: ${datum1.after(datum2)}

Retourneert true als datum1 na datum2 ligt.

${datum1 == datum2}

Alternatief: ${datum1.equals(datum2)}

Retourneet true als beide datums identiek zijn aan elkaar.

${datum1 < datum2}

Alternatief: ${datum1.before(datum2)}

Retourneert true als datum1 vóór datum2 ligt.

Opgelet: hiervoor moet datum van het type datum zijn, niet van het type string. Gebruik indien nodig eerst dateTime().parse(datum) om te converteren.

Getal functies

Overzicht van functies die je kan uitvoeren op een variabele van het type getal.

Operator

Beschrijving

+

Som van twee getalwaardes.

-

Verschil van twee getalwaardes.

/

Quotiënt van twee getalwaardes.

*

Product van twee getalwaardes.

Via haakjes kan je verschillende numerieke bewerkingen groeperen en hiërarchisch met elkaar combineren.

${(getalA + getalB) * 3 / 2}

String functies

Overzicht van een aantal courante functies die je kan uitvoeren op een variabele van het type string.

Functie met voorbeeld

Beschrijving

${‘Hello'.concat(' ').concat('world‘).concat(’!')}

Twee of meerdere string waardes met elkaar concateneren. Retourneert ‘Hello world!’.

${naamProcesVariabele.toString()}

Waarde in procesvariabele omzetten naar een string.

${naamProcesVariabele.contains('Jan')}

Retourneert true als de string ‘Jan’ bevat.

${naamProcesVariabele.startsWith('Jan')}

Retourneert true als de string start met ‘Jan’.

${naamProcesVariabele.endsWith('Jan')}

Retourneert true als de string eindigt met ‘Jan’.

${naamProcesVariabele.toString().matches('Jan Peeters')}

Retourneert true als de waarde van een procesvariabele 100% overeenkomt met de opgegeven waarde ‘Jan Peeters’.

${naamProcesVariabele.equalsIgnoreCase('jan peeters')}

Retourneert true als de input waarde 100% overeenkomt met de opgegeven waarde ‘jan peeters’ zonder rekening te houden met case (uppercase of lowercase).

${' tekst met whitespace voor en na '.trim()}

Verwijdert whitespace voor en na en retourneert ‘tekst met whitespace voor en na’.

${‘Jan Peeters’.toLowerCase()}

Retourneert ‘jan peeters'.

${‘Jan Peeters’.toUpperCase()}

Retourneert ‘JAN PEETERS’.

${'Jan Peeters'.replaceAll('Peeters','Janssen')}

Retourneert ‘Jan Janssen’.

${‘Jan Peeters’.substring(0,2)}

Retourneert ‘Ja’. Dit het stuk van de string dat zich uitstrekt van index positie 0 (inclusief) tot index positie 2 (exclusief).

${‘Jan Peeters’.substring(4)}

Retourneert ‘Peeters’. Dit is het stuk van de string dat zich uitstrekt van index positie 4 tot en met de laatste index positie.

${‘Jan Peeters’.length()}

Retourneert 11, het aantal karakters in de string als integer.

${‘Jan Peeters’.indexOf('P')}

Retourneert de index positie van het eerste voorkomen van het opgegeven karakter of deelstring. Retourneert 4. Retourneert -1 als de waarde niet gevonden wordt.

${''.isEmpty()}

Retourneert true als de string leeg is ('').

Expressie voorbeelden

Voorbeeld 1: default waarde instellen bij lege inputstring

Opgave

${empty referentieNr ? '—' : referentieNr}

Variabelen

CODE
{
  referentieNr = ""
}

Uitkomst

'—'

Uitleg

De expressie ${empty referentieNr ? '—' : referentieNr} gebruikt twee zaken: (1) de operator empty die true is voor null, '' (lege string), [] (lege lijst) en {} (lege map); en (2) de ternary operator [voorwaarde] ? [A] : [B]. Als referentieNr leeg is, krijg je '—' terug; anders krijg je de waarde van referentieNr. In dit voorbeeld is referentieNr = '' (lege string), dus is empty referentieNr true en wordt de dash '—' weergegeven.

Voorbeeld 2: deadline vergelijken met huidige datum

Opgave

${dateTime().parse(deadline).toDate().before(now())}

Variabelen

CODE
{
  deadline = "2025-01-01"
}

Uitkomst

true

Uitleg

De expressie ${dateTime().parse(deadline).toDate().before(now())} controleert of de datum in de variabele deadline vóór het huidige moment ligt. Stap voor stap:

  • deadline is een string met een datum, bv. "2025-01-01".

  • dateTime() geeft een helper-object om met datums/tijden te werken.

  • dateTime().parse(deadline) zet de string om naar een intern datum/tijd-object (1 januari 2025 om 00:00:00 in de ingestelde tijdzone).

  • .toDate() converteert dit naar een java.util.Date.

  • now() geeft het huidige moment als java.util.Date terug.

  • before(now()) vergelijkt beide datums en is true als de deadline in het verleden ligt t.o.v. nu.

Waarom hier "true"? Omdat "2025-01-01" een datum in het verleden is t.o.v. het moment waarop de expressie geëvalueerd wordt (now()).

Voorbeeld 3: string formatteren (title case)

Opgave

${empty naam ? '' : (naam.toLowerCase().substring(0,1).toUpperCase().concat(naam.toLowerCase().substring(1)))}

Variabelen

CODE
{
  "naam":"peeters"
}

Uitkomst

"Peeters"

Uitleg

De expressie ${empty naam ? '' : (naam.toLowerCase().substring(0,1).toUpperCase().concat(naam.toLowerCase().substring(1)))} werkt als volgt (stap-voor-stap):

  • empty naam ? '' : ... — leeg of null? Dan een lege string; anders formatteer verder.

  • naam.toLowerCase() — maak alles kleine letters (bv. "PEETERS" → "peeters").

  • ...substring(0,1).toUpperCase() — pak het eerste teken en maak het hoofdletter ("p" → "P").

  • naam.toLowerCase().substring(1) — neem de rest van de string vanaf index 1 ("eeters").

  • .concat(...) — voeg eerste hoofdletter en rest samen: "P" + "eeters" = "Peeters".

  • Beperking: dit capitaliseert enkel het eerste teken van de volledige string, niet elk afzonderlijk woord ("jan peeters" zou resulteren in "Jan peeters").

Voorbeeld 4: check of specifieke optie meerkeuzeveld aangevinkt is

Opgave

Inclusive gateway met expressies op elk van de uitgaande pijlen.

Ontbijt check

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("hotelFormulier").getField("hotelVoorkeuren")['ontbijt'] == true}

Parkeerplaats check

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("hotelFormulier").getField("hotelVoorkeuren")['parkeerplaats'] == true}

Spa check

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("hotelFormulier").getField("hotelVoorkeuren")['spa'] == true}

Variabelen

CODE
{
  "ontbijt": true,
  "parkeerplaats": false,
  "spa": true
}

Uitkomst

  • Pijl Ontbijt: geactiveerd;

  • Pijl Parkeerplaats: niet geactiveerd;

  • Pijl Spa: geactiveerd.

Uitleg

  • Ontbijt: variabele ontbijt = true, dus de expressie ...['ontbijt'] == true evalueert naar true en activeert die pijl.

  • Parkeerplaats: variabele parkeerplaats = false, dus ...['parkeerplaats'] == true is false; die pijl blijft uit.

  • Spa: variabele spa = true, dus ...['spa'] == true is true en activeert de pijl.

Aangezien het een inclusive gateway is, kunnen meerdere pijlen tegelijk actief zijn; in dit geval Ontbijt en Spa.

Voorbeeld 5: check of aan twee voorwaarden tegelijk is voldaan

Opgave

Exclusive gateway met twee uitgaande pijlen die de twee mogelijke uitkomsten opvangen true of false.

Check indien voldaan aan beide voorwaarden:

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("persoonsFormulier").getField("leeftijd") > 65 && skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("persoonsFormulier").getField("gehuwd") == false}

Check indien niet voldaan aan minstens één van beide voorwaarden:

${skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("persoonsFormulier").getField("leeftijd") <= 65 || skryv.dossierFromScope(execution).getOrCreateDocumentByDefinitionKey("persoonsFormulier").getField("gehuwd") == true}

Uiteraard is het mogelijk om één van beide pijlen aan te duiden als de default. In dat geval is het niet nodig om daar te geïnverteerde expressie te definiëren.

Variabelen

CODE
{
  "persoonsFormulier.leeftijd": 66,
  "persoonsFormulier.gehuwd": true
}

Uitkomst

  • Pijl true (beide voorwaarden voldaan): niet geactiveerd.

  • Pijl false (minstens één voorwaarde niet voldaan): geactiveerd.

Uitleg

  • Voorwaarde 1: leeftijd > 65? 66 > 65 = true.

  • Voorwaarde 2: gehuwd == false? gehuwd = true, dus (true == false) = false.

  • Evaluatie TRUE-pijl (AND): true && false = false → niet geactiveerd.

  • Evaluatie FALSE-pijl (OR): (leeftijd <= 65) || (gehuwd == true) = false || true = true → geactiveerd.

Voorbeeld 6: bedrag berekenen op basis van inkomen en gezinsgrootte

Opgave

${inkomen < 15000 ? (personenTenLaste >= 3 ? 1500 : 1000) : (inkomen < 25000 ? personenTenLaste >= 3 ? 800 : 500) : 0)}

Opmerking: dit is een perfecte use case voor een beslissingstabel. Zeker bij complexere logica.

Variabelen

CODE
{
  "inkomen": 16000,
  "personenTenLaste": 5
}

Uitkomst

800

Uitleg

Stap-voor-stap evaluatie:

  1. Eerste voorwaarde (buitenste ternary links):

    • inkomen < 1500016000 < 15000false

    • We nemen dus NIET het stuk (personenTenLaste >= 3 ? 1500 : 1000), maar gaan naar de rechtertak na de :.

  2. We komen in de rechtertak terecht:

    • (inkomen < 25000 ? (personenTenLaste >= 3 ? 800 : 500) : 0)

  3. Tweede voorwaarde:

    • inkomen < 2500016000 < 25000true

    • We nemen dus het stuk (personenTenLaste >= 3 ? 800 : 500) en niet 0.

  4. Derde voorwaarde (binnenste ternary):

    • personenTenLaste >= 35 >= 3true

    • Daarom kiezen we 800 (en niet 500).

  5. Resultaat van de volledige expressie: 800.

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.