Repository: serverlessworkflow/sdk-java
Pull request #273 (2023-10-20 13:57:47)

Sync branch 4.0.x with main to release 4.0.5
**Many thanks for submitting your Pull Request :heart:!**

**What this PR does / why we need it**:
This PR syncs the changes we made in the main to 4.0.x branch to keep the branch clean for the last fix/CVE upgrades.
This is a tentative to run on Java 1.8. It's possible that we might need to do a few adjustments.

**Special notes for reviewers**:

**Additional information (if needed):**


Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..06541a8
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,14 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+  - package-ecosystem: "maven" # See documentation for possible values
+    directory: "/" # Location of package manifests
+    schedule:
+      interval: "weekly"
+    assignees:
+      - ricardozanini
+      - tsurdilo
diff --git a/.github/project.yml b/.github/project.yml
new file mode 100644
index 0000000..a69b405
--- /dev/null
+++ b/.github/project.yml
@@ -0,0 +1,3 @@
+release:
+  current-version: 4.0.5
+  next-version: 5.0.0-SNAPSHOT
\ No newline at end of file
diff --git a/.github/workflows/maven-deploy.yml b/.github/workflows/maven-deploy.yml
deleted file mode 100644
index 6781247..0000000
--- a/.github/workflows/maven-deploy.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-# This workflow will build a Java project with Maven
-# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
-
-name: Deploy JAVA SDK
-
-on:
-  push:
-    branches:
-      - main
-jobs:
-  publish:
-    runs-on: ubuntu-latest
-    steps:
-      - uses: actions/checkout@v2
-      - name: Set up Maven Central Repository
-        uses: actions/setup-java@v1
-        with:
-          java-version: 1.8
-          server-id: ossrh
-          server-username: MAVEN_USERNAME
-          server-password: MAVEN_PASSWORD
-      - name: Publish package
-        run: mvn -B -f pom.xml deploy
-        env:
-          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
-          MAVEN_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
diff --git a/.github/workflows/maven-verify.yml b/.github/workflows/maven-verify.yml
index 5da5257..44aba63 100644
--- a/.github/workflows/maven-verify.yml
+++ b/.github/workflows/maven-verify.yml
@@ -1,30 +1,28 @@
 # This workflow will build a Java project with Maven
 # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
 
-name: Verify JAVA SDK
+name: sdk-java Verify
 
 on:
   push:
     branches:
-      - main
+      - 4.0.*
   pull_request:
     branches:
-      - main
+      - 4.0.*
 jobs:
   build:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
-    - name: Set up JDK 1.8
-      uses: actions/setup-java@v1
-      with:
-        java-version: 1.8
-    - name: Cache Maven packages
-      uses: actions/cache@v2
-      with:
-        path: ~/.m2
-        key: ${{ runner.os }}-m2-${{ hashFiles('pom.xml') }}
-        restore-keys: ${{ runner.os }}-m2
-    - name: Verify with Maven
-      run: |
-        mvn -B -f pom.xml clean install verify
+      - uses: actions/checkout@v2
+
+      - name: Set up JDK 1.8
+        uses: actions/setup-java@v3
+        with:
+          distribution: temurin
+          java-version: 8
+          cache: 'maven'
+
+      - name: Verify with Maven
+        run: |
+          mvn -B -f pom.xml clean install verify
diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml
new file mode 100644
index 0000000..ce904c7
--- /dev/null
+++ b/.github/workflows/pre-release.yml
@@ -0,0 +1,25 @@
+name: sdk-java Pre Release
+
+on:
+  pull_request:
+    paths:
+      - '.github/project.yml'
+
+jobs:
+  release:
+    runs-on: ubuntu-latest
+    name: pre release
+
+    steps:
+      - uses: radcortez/project-metadata-action@master
+        name: retrieve project metadata
+        id: metadata
+        with:
+          github-token: ${{secrets.GITHUB_TOKEN}}
+          metadata-file-path: '.github/project.yml'
+
+      - name: Validate version
+        if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT')
+        run: |
+          echo '::error::Cannot release a SNAPSHOT version.'
+          exit 1
\ No newline at end of file
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..f2341c8
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,58 @@
+name: sdk-java Release
+
+on:
+  pull_request:
+    types: [closed]
+    paths:
+      - '.github/project.yml'
+
+jobs:
+  release:
+    runs-on: ubuntu-latest
+    name: release
+    if: ${{github.event.pull_request.merged == true}}
+
+    steps:
+      - uses: radcortez/project-metadata-action@main
+        name: Retrieve project metadata
+        id: metadata
+        with:
+          github-token: ${{secrets.GITHUB_TOKEN}}
+          metadata-file-path: '.github/project.yml'
+
+      - uses: actions/checkout@v3
+
+      - name: Import GPG key
+        id: import_gpg
+        uses: crazy-max/ghaction-import-gpg@v5
+        with:
+          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
+          passphrase: ${{ secrets.GPG_PASSPHRASE }}
+
+      - name: Set up JDK 1.8
+        uses: actions/setup-java@v3
+        with:
+          distribution: temurin
+          java-version: 8
+          cache: 'maven'
+          server-id: ossrh
+          server-username: MAVEN_USERNAME
+          server-password: MAVEN_PASSWORD
+
+      - name: Configure Git author
+        run: |
+          git config --local user.email "action@github.com"
+          git config --local user.name "GitHub Action"
+
+      - name: Maven release ${{steps.metadata.outputs.current-version}}
+        run: |
+          mvn -B release:prepare -Prelease -DreleaseVersion=${{steps.metadata.outputs.current-version}} -DdevelopmentVersion=${{steps.metadata.outputs.next-version}}
+          mvn -B release:perform -Darguments=-DperformRelease -DperformRelease -Prelease
+        env:
+          MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+          MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }}
+
+      - name: Push changes to ${{github.base_ref}} branch
+        run: |
+          git push
+          git push origin ${{steps.metadata.outputs.current-version}}
diff --git a/api/pom.xml b/api/pom.xml
index 8b27e85..63ba1ef 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -26,31 +26,19 @@
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-core</artifactId>
-            <version>[2.13.0,)</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
-            <version>[2.13.0,)</version>
         </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.dataformat</groupId>
             <artifactId>jackson-dataformat-yaml</artifactId>
-            <version>[2.13.0,)</version>
         </dependency>
         <dependency>
             <groupId>javax.validation</groupId>
             <artifactId>validation-api</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.json</groupId>
-            <artifactId>json</artifactId>
-        </dependency>
-        <dependency>
-            <groupId>com.github.erosb</groupId>
-            <artifactId>everit-json-schema</artifactId>
-        </dependency>
-
         <!-- test -->
         <dependency>
             <groupId>org.junit.jupiter</groupId>
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
index abdb058..aa078cb 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/AuthDeserializer.java
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.auth.AuthDefinition;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@ import io.serverlessworkflow.api.workflow.Auth;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,21 +67,8 @@ public class AuthDeserializer extends StdDeserializer<Auth> {
     } else {
       String authFileDef = node.asText();
       String authFileSrc = Utils.getResourceFileAsString(authFileDef);
-      JsonNode authRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (authFileSrc != null && authFileSrc.trim().length() > 0) {
-        // if its a yaml def convert to json first
-        if (!authFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(authFileSrc, Object.class);
-
-          authRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          authRefNode = jsonWriter.readTree(new JSONObject(authFileSrc).toString());
-        }
-
+        JsonNode authRefNode = Utils.getNode(authFileSrc);
         JsonNode refAuth = authRefNode.get("auth");
         if (refAuth != null) {
           for (final JsonNode nodeEle : refAuth) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
index c3789b5..3859273 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/ConstantsDeserializer.java
@@ -18,14 +18,11 @@ package io.serverlessworkflow.api.deserializers;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
 import io.serverlessworkflow.api.workflow.Constants;
 import java.io.IOException;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,21 +60,8 @@ public class ConstantsDeserializer extends StdDeserializer<Constants> {
     } else {
       String constantsFileDef = node.asText();
       String constantsFileSrc = Utils.getResourceFileAsString(constantsFileDef);
-      JsonNode constantsRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (constantsFileSrc != null && constantsFileSrc.trim().length() > 0) {
-        // if its a yaml def convert to json first
-        if (!constantsFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(constantsFileSrc, Object.class);
-
-          constantsRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          constantsRefNode = jsonWriter.readTree(new JSONObject(constantsFileSrc).toString());
-        }
-
+        JsonNode constantsRefNode = Utils.getNode(constantsFileSrc);
         JsonNode refConstants = constantsRefNode.get("constants");
         if (refConstants != null) {
           constantsDefinition = refConstants;
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
index beedc7d..6fe366e 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/ErrorsDeserializer.java
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.error.ErrorDefinition;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@ import io.serverlessworkflow.api.workflow.Errors;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,21 +67,8 @@ public class ErrorsDeserializer extends StdDeserializer<Errors> {
     } else {
       String errorsFileDef = node.asText();
       String errorsFileSrc = Utils.getResourceFileAsString(errorsFileDef);
-      JsonNode errorsRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (errorsFileSrc != null && errorsFileSrc.trim().length() > 0) {
-        // if its a yaml def convert to json first
-        if (!errorsFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(errorsFileSrc, Object.class);
-
-          errorsRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          errorsRefNode = jsonWriter.readTree(new JSONObject(errorsFileSrc).toString());
-        }
-
+        JsonNode errorsRefNode = Utils.getNode(errorsFileSrc);
         JsonNode refErrors = errorsRefNode.get("errors");
         if (refErrors != null) {
           for (final JsonNode nodeEle : refErrors) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
index cfa207d..a02fdf4 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/EventsDeserializer.java
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.events.EventDefinition;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@ import io.serverlessworkflow.api.workflow.Events;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,21 +67,9 @@ public class EventsDeserializer extends StdDeserializer<Events> {
     } else {
       String eventsFileDef = node.asText();
       String eventsFileSrc = Utils.getResourceFileAsString(eventsFileDef);
-      JsonNode eventsRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (eventsFileSrc != null && eventsFileSrc.trim().length() > 0) {
         // if its a yaml def convert to json first
-        if (!eventsFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(eventsFileSrc, Object.class);
-
-          eventsRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          eventsRefNode = jsonWriter.readTree(new JSONObject(eventsFileSrc).toString());
-        }
-
+        JsonNode eventsRefNode = Utils.getNode(eventsFileSrc);
         JsonNode refEvents = eventsRefNode.get("events");
         if (refEvents != null) {
           for (final JsonNode nodeEle : refEvents) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
index c27e2c4..b706b2d 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/FunctionsDeserializer.java
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.functions.FunctionDefinition;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@ import io.serverlessworkflow.api.workflow.Functions;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,20 +67,9 @@ public class FunctionsDeserializer extends StdDeserializer<Functions> {
       String functionsFileDef = node.asText();
       String functionsFileSrc = Utils.getResourceFileAsString(functionsFileDef);
       JsonNode functionsRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (functionsFileSrc != null && functionsFileSrc.trim().length() > 0) {
         // if its a yaml def convert to json first
-        if (!functionsFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(functionsFileSrc, Object.class);
-
-          functionsRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          functionsRefNode = jsonWriter.readTree(new JSONObject(functionsFileSrc).toString());
-        }
-
+        functionsRefNode = Utils.getNode(functionsFileSrc);
         JsonNode refFunctions = functionsRefNode.get("functions");
         if (refFunctions != null) {
           for (final JsonNode nodeEle : refFunctions) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
index ff2fe44..9eb47b5 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/RetriesDeserializer.java
@@ -20,7 +20,6 @@ import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.retry.RetryDefinition;
 import io.serverlessworkflow.api.utils.Utils;
@@ -28,7 +27,6 @@ import io.serverlessworkflow.api.workflow.Retries;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,21 +67,8 @@ public class RetriesDeserializer extends StdDeserializer<Retries> {
     } else {
       String retriesFileDef = node.asText();
       String retriesFileSrc = Utils.getResourceFileAsString(retriesFileDef);
-      JsonNode retriesRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (retriesFileSrc != null && retriesFileSrc.trim().length() > 0) {
-        // if its a yaml def convert to json first
-        if (!retriesFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(retriesFileSrc, Object.class);
-
-          retriesRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          retriesRefNode = jsonWriter.readTree(new JSONObject(retriesFileSrc).toString());
-        }
-
+        JsonNode retriesRefNode = Utils.getNode(retriesFileSrc);
         JsonNode refRetries = retriesRefNode.get("retries");
         if (refRetries != null) {
           for (final JsonNode nodeEle : refRetries) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java b/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
index e9ec05e..60cc2a8 100644
--- a/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
+++ b/api/src/main/java/io/serverlessworkflow/api/deserializers/SecretsDeserializer.java
@@ -18,16 +18,13 @@ package io.serverlessworkflow.api.deserializers;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import io.serverlessworkflow.api.interfaces.WorkflowPropertySource;
 import io.serverlessworkflow.api.utils.Utils;
 import io.serverlessworkflow.api.workflow.Secrets;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -66,21 +63,9 @@ public class SecretsDeserializer extends StdDeserializer<Secrets> {
     } else {
       String secretsFileDef = node.asText();
       String secretsFileSrc = Utils.getResourceFileAsString(secretsFileDef);
-      JsonNode secretsRefNode;
-      ObjectMapper jsonWriter = new ObjectMapper();
       if (secretsFileSrc != null && secretsFileSrc.trim().length() > 0) {
         // if its a yaml def convert to json first
-        if (!secretsFileSrc.trim().startsWith("{")) {
-          // convert yaml to json to validate
-          ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-          Object obj = yamlReader.readValue(secretsFileSrc, Object.class);
-
-          secretsRefNode =
-              jsonWriter.readTree(new JSONObject(jsonWriter.writeValueAsString(obj)).toString());
-        } else {
-          secretsRefNode = jsonWriter.readTree(new JSONObject(secretsFileSrc).toString());
-        }
-
+        JsonNode secretsRefNode = Utils.getNode(secretsFileSrc);
         JsonNode refSecrets = secretsRefNode.get("secrets");
         if (refSecrets != null) {
           for (final JsonNode nodeEle : refSecrets) {
diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java
new file mode 100644
index 0000000..eb34b0e
--- /dev/null
+++ b/api/src/main/java/io/serverlessworkflow/api/mapper/JsonObjectMapperFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020-Present The Serverless Workflow Specification Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.serverlessworkflow.api.mapper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JsonObjectMapperFactory {
+
+  private static final ObjectMapper instance = new JsonObjectMapper();
+
+  public static final ObjectMapper mapper() {
+    return instance;
+  }
+}
diff --git a/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java
new file mode 100644
index 0000000..04371db
--- /dev/null
+++ b/api/src/main/java/io/serverlessworkflow/api/mapper/YamlObjectMapperFactory.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2020-Present The Serverless Workflow Specification Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.serverlessworkflow.api.mapper;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class YamlObjectMapperFactory {
+
+  private static final ObjectMapper instance = new YamlObjectMapper();
+
+  public static final ObjectMapper mapper() {
+    return instance;
+  }
+}
diff --git a/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java b/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java
deleted file mode 100644
index a4da238..0000000
--- a/api/src/main/java/io/serverlessworkflow/api/schemaclient/ResourceSchemaClient.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2020-Present The Serverless Workflow Specification Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.serverlessworkflow.api.schemaclient;
-
-import java.io.InputStream;
-import java.util.Objects;
-import org.everit.json.schema.loader.SchemaClient;
-
-public class ResourceSchemaClient implements SchemaClient {
-
-  @SuppressWarnings("unused")
-  private final SchemaClient fallbackClient;
-
-  private final String baseResourcePath = "/schema/";
-
-  public ResourceSchemaClient(SchemaClient fallbackClient) {
-    this.fallbackClient = Objects.requireNonNull(fallbackClient, "fallbackClient cannot be null");
-  }
-
-  @Override
-  public InputStream get(String path) {
-    path = path.substring("https://wg-serverless.org/".length());
-    return this.getClass().getResourceAsStream(baseResourcePath + path);
-  }
-}
diff --git a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java b/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
index 3e4b427..9bdce41 100644
--- a/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
+++ b/api/src/main/java/io/serverlessworkflow/api/utils/Utils.java
@@ -15,6 +15,11 @@
  */
 package io.serverlessworkflow.api.utils;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.serverlessworkflow.api.mapper.JsonObjectMapperFactory;
+import io.serverlessworkflow.api.mapper.YamlObjectMapperFactory;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
@@ -34,4 +39,14 @@ public class Utils {
       }
     }
   }
+
+  public static ObjectMapper getObjectMapper(String source) {
+    return !source.trim().startsWith("{")
+        ? YamlObjectMapperFactory.mapper()
+        : JsonObjectMapperFactory.mapper();
+  }
+
+  public static JsonNode getNode(String source) throws JsonProcessingException {
+    return getObjectMapper(source).readTree(source);
+  }
 }
diff --git a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java b/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
index 830bb50..847380f 100644
--- a/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
+++ b/api/src/main/java/io/serverlessworkflow/api/validation/WorkflowSchemaLoader.java
@@ -15,26 +15,23 @@
  */
 package io.serverlessworkflow.api.validation;
 
-import io.serverlessworkflow.api.schemaclient.ResourceSchemaClient;
-import org.everit.json.schema.Schema;
-import org.everit.json.schema.loader.SchemaLoader;
-import org.everit.json.schema.loader.internal.DefaultSchemaClient;
-import org.json.JSONObject;
-import org.json.JSONTokener;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+import java.io.UncheckedIOException;
 
 public class WorkflowSchemaLoader {
-  private static final JSONObject workflowSchema =
-      new JSONObject(
-          new JSONTokener(WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json")));
 
-  public static Schema getWorkflowSchema() {
-    SchemaLoader schemaLoader =
-        SchemaLoader.builder()
-            .schemaClient(new ResourceSchemaClient(new DefaultSchemaClient()))
-            .schemaJson(workflowSchema)
-            .resolutionScope("classpath:schema")
-            .draftV7Support()
-            .build();
-    return schemaLoader.load().build();
+  public static JsonNode getWorkflowSchema() {
+    try {
+      return ObjectMapperHolder.objectMapper.readTree(
+          WorkflowSchemaLoader.class.getResourceAsStream("/schema/workflow.json"));
+    } catch (IOException e) {
+      throw new UncheckedIOException(e);
+    }
+  }
+
+  private static class ObjectMapperHolder {
+    public static final ObjectMapper objectMapper = new ObjectMapper();
   }
 }
diff --git a/api/src/main/resources/schema/produce/produceevent.json b/api/src/main/resources/schema/produce/produceevent.json
index b5bb7d5..f094824 100644
--- a/api/src/main/resources/schema/produce/produceevent.json
+++ b/api/src/main/resources/schema/produce/produceevent.json
@@ -10,6 +10,11 @@
     "data": {
       "type": "string",
       "description": "Workflow expression which selects parts of the states data output to become the data of the produced event"
+    },
+    "contextAttributes": {
+      "type": "object",
+      "description": "Add additional event extension context attributes",
+      "existingJavaType": "java.util.Map<String, String>"
     }
   },
   "required": [
diff --git a/api/src/main/resources/schema/workflow.json b/api/src/main/resources/schema/workflow.json
index 3ed9ce5..f8309b6 100644
--- a/api/src/main/resources/schema/workflow.json
+++ b/api/src/main/resources/schema/workflow.json
@@ -1,5 +1,5 @@
 {
-  "$id": "https://wg-serverless.org/workflow.schema.json",
+  "$id": "classpath:schema/workflow.schema.json",
   "$schema": "http://json-schema.org/draft-07/schema#",
   "description": "Serverless Workflow is a vendor-neutral specification for defining the model of workflows responsible for orchestrating event-driven serverless applications.",
   "type": "object",
@@ -11,7 +11,8 @@
   "properties": {
     "id": {
       "type": "string",
-      "description": "Workflow unique identifier"
+      "description": "Workflow unique identifier",
+      "minLength": 1
     },
     "key": {
       "type": "string",
@@ -159,6 +160,7 @@
     }
   },
  "required": [
+        "id",
         "name",
         "version",
         "states"
diff --git a/code-of-conduct.md b/code-of-conduct.md
index ddd14b6..97a8526 100644
--- a/code-of-conduct.md
+++ b/code-of-conduct.md
@@ -1,58 +1,11 @@
-## CNCF Community Code of Conduct v1.0
+# Code of Conduct
 
-Other languages available:
-- [Chinese/中文](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/zh.md)
-- [German/Deutsch](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/de.md)
-- [Spanish/Español](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/es.md)
-- [French/Français](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/fr.md)
-- [Italian/Italiano](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/it.md)
-- [Japanese/日本語](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/jp.md)
-- [Korean/한국어](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ko.md)
-- [Ukrainian/Українська](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/uk.md)
-- [Russian/Русский](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ru.md)
-- [Portuguese/Português](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/pt.md)
-- [Arabic/العربية](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/ar.md)
-- [Polish/Polski](https://github.com/cncf/foundation/blob/master/code-of-conduct-languages/pl.md)
+We follow the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/main/code-of-conduct.md).
 
-### Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of fostering
-an open and welcoming community, we pledge to respect all people who contribute
-through reporting issues, posting feature requests, updating documentation,
-submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for
-everyone, regardless of level of experience, gender, gender identity and expression,
-sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
-religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing others' private information, such as physical or electronic addresses,
- without explicit permission
-* Other unethical or unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are not
-aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers
-commit themselves to fairly and consistently applying these principles to every aspect
-of managing this project. Project maintainers who do not follow or enforce the Code of
-Conduct may be permanently removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior in Kubernetes may be reported by contacting the [Kubernetes Code of Conduct Committee](https://git.k8s.io/community/committee-code-of-conduct) via conduct@kubernetes.io. For other projects, please contact a CNCF project maintainer or our mediator, Mishi Choudhary via mishi@linux.com.
-
-This Code of Conduct is adapted from the Contributor Covenant
-(<http://contributor-covenant.org>), version 1.2.0, available at
-<http://contributor-covenant.org/version/1/2/0/>
-
-### CNCF Events Code of Conduct
-
-CNCF events are governed by the Linux Foundation [Code of Conduct](https://events.linuxfoundation.org/code-of-conduct/) available on the event page.
-This is designed to be compatible with the above policy and also includes more details on responding to incidents.
\ No newline at end of file
+<!-- TODO: Decide who will handle Code of Conduct reports and replace [INSERT EMAIL ADDRESS]
+    with an email address in the paragraph below. We recommend using a mailing list to handle reports.
+    If your project isn't prepared to handle reports, remove the project email address and just have
+    reporters send to conduct@cncf.io.
+-->
+Please contact the [CNCF Code of Conduct Committee](mailto:conduct@cncf.io)
+in order to report violations of the Code of Conduct.
diff --git a/pom.xml b/pom.xml
index 53a2abf..2248641 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,87 +1,96 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-    <modelVersion>4.0.0</modelVersion>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
 
-    <groupId>io.serverlessworkflow</groupId>
-    <artifactId>serverlessworkflow-parent</artifactId>
-    <version>4.0.x</version>
-    <packaging>pom</packaging>
+  <groupId>io.serverlessworkflow</groupId>
+  <artifactId>serverlessworkflow-parent</artifactId>
+  <version>4.0.x</version>
+  <packaging>pom</packaging>
 
-    <name>Serverless Workflow :: Parent</name>
-    <url>https://serverlessworkflow.io/sdk-java/</url>
-    <description>Java SDK for Serverless Workflow Specification</description>
-    <inceptionYear>2020</inceptionYear>
-    <organization>
-        <name>CNCF</name>
-        <url>https://www.cncf.io//</url>
-    </organization>
-    <licenses>
-        <license>
-            <name>The Apache Software License, Version 2.0</name>
-            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
-            <distribution>repo</distribution>
-        </license>
-    </licenses>
+  <name>Serverless Workflow :: Parent</name>
+  <url>https://serverlessworkflow.io/sdk-java/</url>
+  <description>Java SDK for Serverless Workflow Specification</description>
+  <inceptionYear>2020</inceptionYear>
+  <developers>
+    <developer>
+      <id>serverless-workflow</id>
+      <name>Serverless Workflow Specification Authors</name>
+      <organization>CNCF</organization>
+    </developer>
+  </developers>
+  <organization>
+    <name>CNCF</name>
+    <url>https://www.cncf.io//</url>
+  </organization>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:git:git@github.com:serverlessworkflow/sdk-java.git</connection>
+    <developerConnection>scm:git:git@github.com:serverlessworkflow/sdk-java.git</developerConnection>
+    <url>https://github.com/serverlessworkflow/sdk-java</url>
+    <tag>HEAD</tag>
+  </scm>
 
-    <scm>
-        <connection>scm:git:git://github.com/serverlessworkflow/sdk-java.git</connection>
-        <developerConnection>scm:git:git@github.com:serverlessworkflow/sdk-java.git</developerConnection>
-        <url>https://github.com/serverlessworkflow/sdk-java</url>
-    </scm>
+  <modules>
+    <module>api</module>
+    <module>spi</module>
+    <module>validation</module>
+    <module>diagram</module>
+    <module>utils</module>
+  </modules>
 
-    <developers>
-        <developer>
-            <id>tsurdilo</id>
-            <name>Tihomir Surdilovic</name>
-        </developer>
-    </developers>
+  <properties>
+    <java.version>1.8</java.version>
+    <maven.compiler.source>${java.version}</maven.compiler.source>
+    <maven.compiler.target>${java.version}</maven.compiler.target>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <version.maven>3.6.2</version.maven>
 
-    <modules>
-        <module>api</module>
-        <module>spi</module>
-        <module>validation</module>
-        <module>diagram</module>
-        <module>utils</module>
-    </modules>
+    <!-- Plugin versions, please keep in alphabetical order -->
+    <version.buildnumber.plugin>3.2.0</version.buildnumber.plugin>
+    <version.checkstyle.plugin>3.1.1</version.checkstyle.plugin>
+    <version.compiler.plugin>3.8.1</version.compiler.plugin>
+    <version.deploy.plugin>2.8.2</version.deploy.plugin>
+    <version.enforcer.plugin>3.0.0-M2</version.enforcer.plugin>
+    <version.failsafe.plugin>3.1.2</version.failsafe.plugin>
+    <version.fmt-maven-plugin>2.9.1</version.fmt-maven-plugin>
+    <version.gpg.plugin>3.1.0</version.gpg.plugin>
+    <version.jar.plugin>3.2.0</version.jar.plugin>
+    <version.jdk>${java.version}</version.jdk>
+    <version.jsonschema2pojo-maven-plugin>1.0.1</version.jsonschema2pojo-maven-plugin>
+    <version.source.plugin>3.3.0</version.source.plugin>
+    <version.surefire.plugin>2.22.0</version.surefire.plugin>
 
-    <properties>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
-        <java.version>1.8</java.version>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <version.maven>3.6.2</version.maven>
-        <version.enforcer.plugin>3.0.0-M2</version.enforcer.plugin>
-        <version.jdk>8</version.jdk>
-        <version.compiler.plugin>3.8.1</version.compiler.plugin>
-        <version.surefire.plugin>2.22.0</version.surefire.plugin>
-        <version.failsafe.plugin>2.22.0</version.failsafe.plugin>
-        <version.checkstyle.plugin>3.1.1</version.checkstyle.plugin>
-        <version.deploy.plugin>2.8.2</version.deploy.plugin>
 
-        <version.org.slf4j>1.7.25</version.org.slf4j>
-        <version.com.fasterxml.jackson>2.10.3</version.com.fasterxml.jackson>
-        <version.javax.validation>2.0.1.Final</version.javax.validation>
-        <version.org.junit.minor>6.0</version.org.junit.minor>
-        <version.org.junit>5.${version.org.junit.minor}</version.org.junit>
-        <version.org.junit.jupiter>${version.org.junit}</version.org.junit.jupiter>
-        <version.org.mockito>3.0.0</version.org.mockito>
-        <version.ch.qos.logback>1.4.8</version.ch.qos.logback>
-        <version.org.assertj>3.13.2</version.org.assertj>
-        <version.jsonschema2pojo-maven-plugin>1.0.1</version.jsonschema2pojo-maven-plugin>
-        <commons.lang.version>3.9</commons.lang.version>
-        <hamcrest.version>1.3</hamcrest.version>
-        <jsonassert.version>1.5.0</jsonassert.version>
-        <json.schema.validation.version>1.14.1</json.schema.validation.version>
-        <version.json>20230618</version.json>
-        <version.thymeleaf>3.0.11.RELEASE</version.thymeleaf>
-        <version.plantuml>8059</version.plantuml>
-        <version.graphviz>0.17.0</version.graphviz>
-        <version.fmt-maven-plugin>2.9</version.fmt-maven-plugin>
-        <version.jar.plugin>3.2.0</version.jar.plugin>
-        <!-- Checkstyle props -->
-        <checkstyle.failOnViolation>true</checkstyle.failOnViolation>
-        <checkstyle.header.template><![CDATA[
+    <!-- Dependencies versions, please keep in alphabetical order -->
+    <version.ch.qos.logback>1.4.9</version.ch.qos.logback>
+    <version.com.fasterxml.jackson>2.15.3</version.com.fasterxml.jackson>
+    <version.com.networknt>1.0.87</version.com.networknt>
+    <version.commons.lang>3.13.0</version.commons.lang>
+    <version.graphviz>0.17.0</version.graphviz>
+    <version.hamcrest>1.3</version.hamcrest>
+    <version.javax.validation>2.0.1.Final</version.javax.validation>
+    <version.jsonassert>1.5.0</version.jsonassert>
+    <version.org.assertj>3.13.2</version.org.assertj>
+    <version.org.junit.jupiter>${version.org.junit}</version.org.junit.jupiter>
+    <version.org.junit.minor>6.0</version.org.junit.minor>
+    <version.org.junit>5.${version.org.junit.minor}</version.org.junit>
+    <version.org.mockito>5.6.0</version.org.mockito>
+    <version.org.slf4j>1.7.25</version.org.slf4j>
+    <version.plantuml>8059</version.plantuml>
+    <version.thymeleaf>3.1.2.RELEASE</version.thymeleaf>
+
+
+    <!-- Checkstyle props -->
+    <checkstyle.failOnViolation>true</checkstyle.failOnViolation>
+    <checkstyle.header.template><![CDATA[
 ^\/\*$\n^
 \* Copyright \d\d\d\d-Present The Serverless Workflow Specification Authors$\n^
 \*$\n^
@@ -98,280 +107,387 @@
 \* limitations under the License\.$\n^
 \*\/$
 ]]>
-        </checkstyle.header.template>
-        <checkstyle.header.extensions>java</checkstyle.header.extensions>
-        <checkstyle.logViolationsToConsole>true</checkstyle.logViolationsToConsole>
-    </properties>
+    </checkstyle.header.template>
+    <checkstyle.header.extensions>java</checkstyle.header.extensions>
+    <checkstyle.logViolationsToConsole>true</checkstyle.logViolationsToConsole>
+  </properties>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>${version.org.slf4j}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>jcl-over-slf4j</artifactId>
+        <version>${version.org.slf4j}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.fasterxml.jackson.core</groupId>
+        <artifactId>jackson-core</artifactId>
+        <version>${version.com.fasterxml.jackson}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.fasterxml.jackson.core</groupId>
+        <artifactId>jackson-databind</artifactId>
+        <version>${version.com.fasterxml.jackson}</version>
+      </dependency>
+      <dependency>
+        <groupId>com.networknt</groupId>
+        <artifactId>json-schema-validator</artifactId>
+        <version>${version.com.networknt}</version>
+        <exclusions>
+          <exclusion>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+          </exclusion>
+        </exclusions>
+      </dependency>
+      <dependency>
+        <groupId>com.fasterxml.jackson.dataformat</groupId>
+        <artifactId>jackson-dataformat-yaml</artifactId>
+        <version>${version.com.fasterxml.jackson}</version>
+      </dependency>
+      <dependency>
+        <groupId>javax.validation</groupId>
+        <artifactId>validation-api</artifactId>
+        <version>${version.javax.validation}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.commons</groupId>
+        <artifactId>commons-lang3</artifactId>
+        <version>${version.commons.lang}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.thymeleaf</groupId>
+        <artifactId>thymeleaf</artifactId>
+        <version>${version.thymeleaf}</version>
+      </dependency>
+      <dependency>
+        <groupId>net.sourceforge.plantuml</groupId>
+        <artifactId>plantuml</artifactId>
+        <version>${version.plantuml}</version>
+      </dependency>
+      <dependency>
+        <groupId>guru.nidi</groupId>
+        <artifactId>graphviz-java</artifactId>
+        <version>${version.graphviz}</version>
+      </dependency>
+
+      <!-- test -->
+      <dependency>
+        <groupId>org.junit.jupiter</groupId>
+        <artifactId>junit-jupiter-api</artifactId>
+        <version>${version.org.junit.jupiter}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.junit.jupiter</groupId>
+        <artifactId>junit-jupiter-engine</artifactId>
+        <version>${version.org.junit.jupiter}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.junit.jupiter</groupId>
+        <artifactId>junit-jupiter-params</artifactId>
+        <version>${version.org.junit.jupiter}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-core</artifactId>
+        <version>${version.org.mockito}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>ch.qos.logback</groupId>
+        <artifactId>logback-classic</artifactId>
+        <version>${version.ch.qos.logback}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.assertj</groupId>
+        <artifactId>assertj-core</artifactId>
+        <version>${version.org.assertj}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.hamcrest</groupId>
+        <artifactId>hamcrest-library</artifactId>
+        <version>${version.hamcrest}</version>
+        <scope>test</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.skyscreamer</groupId>
+        <artifactId>jsonassert</artifactId>
+        <version>${version.jsonassert}</version>
+        <scope>test</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
 
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.slf4j</groupId>
-                <artifactId>slf4j-api</artifactId>
-                <version>${version.org.slf4j}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.slf4j</groupId>
-                <artifactId>jcl-over-slf4j</artifactId>
-                <version>${version.org.slf4j}</version>
-            </dependency>
-            <dependency>
-                <groupId>com.fasterxml.jackson.core</groupId>
-                <artifactId>jackson-core</artifactId>
-                <version>${version.com.fasterxml.jackson}</version>
-            </dependency>
-            <dependency>
-                <groupId>com.fasterxml.jackson.core</groupId>
-                <artifactId>jackson-databind</artifactId>
-                <version>${version.com.fasterxml.jackson}</version>
-            </dependency>
-            <dependency>
-                <groupId>com.fasterxml.jackson.dataformat</groupId>
-                <artifactId>jackson-dataformat-yaml</artifactId>
-                <version>${version.com.fasterxml.jackson}</version>
-            </dependency>
-            <dependency>
-                <groupId>javax.validation</groupId>
-                <artifactId>validation-api</artifactId>
-                <version>${version.javax.validation}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.commons</groupId>
-                <artifactId>commons-lang3</artifactId>
-                <version>${commons.lang.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>com.github.erosb</groupId>
-                <artifactId>everit-json-schema</artifactId>
-                <version>${json.schema.validation.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <groupId>commons-logging</groupId>
-                        <artifactId>commons-logging</artifactId>
-                    </exclusion>
-                </exclusions>
-            </dependency>
-            <dependency>
-                <groupId>org.json</groupId>
-                <artifactId>json</artifactId>
-                <version>${version.json}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.thymeleaf</groupId>
-                <artifactId>thymeleaf</artifactId>
-                <version>${version.thymeleaf}</version>
-            </dependency>
-            <dependency>
-                <groupId>net.sourceforge.plantuml</groupId>
-                <artifactId>plantuml</artifactId>
-                <version>${version.plantuml}</version>
-            </dependency>
-            <dependency>
-                <groupId>guru.nidi</groupId>
-                <artifactId>graphviz-java</artifactId>
-                <version>${version.graphviz}</version>
-            </dependency>
+  <build>
+    <plugins>
+      <!-- Set properties containing the scm revision -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>buildnumber-maven-plugin</artifactId>
+        <version>${version.buildnumber.plugin}</version>
+        <executions>
+          <execution>
+            <id>get-scm-revision</id>
+            <phase>initialize</phase>
+            <goals>
+              <goal>create</goal>
+            </goals>
+            <configuration>
+              <doCheck>false</doCheck>
+              <doUpdate>false</doUpdate>
+              <revisionOnScmFailure>UNKNOWN</revisionOnScmFailure>
+              <getRevisionOnlyOnce>true</getRevisionOnlyOnce>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>${version.compiler.plugin}</version>
+        <configuration>
+          <showDeprecation>true</showDeprecation>
+          <showWarnings>true</showWarnings>
+          <source>${maven.compiler.source}</source>
+          <target>${maven.compiler.target}</target>
+          <testSource>${maven.compiler.source}</testSource>
+          <testTarget>${maven.compiler.target}</testTarget>
+          <parameters>true</parameters>
+          <compilerArgs>
+            <arg>-Xlint:unchecked</arg>
+          </compilerArgs>
+        </configuration>
+      </plugin>
+    </plugins>
 
-            <!-- test -->
-            <dependency>
-                <groupId>org.junit.jupiter</groupId>
-                <artifactId>junit-jupiter-api</artifactId>
-                <version>${version.org.junit.jupiter}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.junit.jupiter</groupId>
-                <artifactId>junit-jupiter-engine</artifactId>
-                <version>${version.org.junit.jupiter}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.junit.jupiter</groupId>
-                <artifactId>junit-jupiter-params</artifactId>
-                <version>${version.org.junit.jupiter}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.mockito</groupId>
-                <artifactId>mockito-core</artifactId>
-                <version>${version.org.mockito}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>ch.qos.logback</groupId>
-                <artifactId>logback-classic</artifactId>
-                <version>${version.ch.qos.logback}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.assertj</groupId>
-                <artifactId>assertj-core</artifactId>
-                <version>${version.org.assertj}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.hamcrest</groupId>
-                <artifactId>hamcrest-library</artifactId>
-                <version>${hamcrest.version}</version>
-                <scope>test</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.skyscreamer</groupId>
-                <artifactId>jsonassert</artifactId>
-                <version>${jsonassert.version}</version>
-                <scope>test</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-gpg-plugin</artifactId>
+          <version>${version.gpg.plugin}</version>
+        </plugin>
+        <plugin>
+          <artifactId>maven-deploy-plugin</artifactId>
+          <version>${version.deploy.plugin}</version>
+          <configuration>
+            <retryFailedDeploymentCount>10</retryFailedDeploymentCount>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-enforcer-plugin</artifactId>
+          <version>${version.enforcer.plugin}</version>
+          <executions>
+            <execution>
+              <id>enforce-versions</id>
+              <goals>
+                <goal>enforce</goal>
+              </goals>
+              <configuration>
+                <rules>
+                  <requireMavenVersion>
+                    <version>${version.maven}</version>
+                  </requireMavenVersion>
+                  <requireJavaVersion>
+                    <version>${version.jdk}</version>
+                  </requireJavaVersion>
+                </rules>
+              </configuration>
+            </execution>
+          </executions>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-source-plugin</artifactId>
+          <version>${version.source.plugin}</version>
+          <executions>
+            <execution>
+              <id>attach-sources</id>
+              <goals>
+                <goal>jar-no-fork</goal>
+              </goals>
+            </execution>
+          </executions>
+          <configuration>
+            <archive>
+              <index>true</index>
+              <manifest>
+                <addDefaultSpecificationEntries>
+                  true
+                </addDefaultSpecificationEntries>
+                <addDefaultImplementationEntries>
+                  true
+                </addDefaultImplementationEntries>
+              </manifest>
+              <manifestEntries>
+                <Implementation-URL>${project.url}</Implementation-URL>
+                <Java-Version>${java.version}</Java-Version>
+                <Java-Vendor>${java.vendor}</Java-Vendor>
+                <Os-Name>${os.name}</Os-Name>
+                <Os-Arch>${os.arch}</Os-Arch>
+                <Os-Version>${os.version}</Os-Version>
+                <Scm-Url>${project.scm.url}</Scm-Url>
+                <Scm-Connection>${project.scm.connection}</Scm-Connection>
+                <Scm-Revision>${buildNumber}</Scm-Revision>
+              </manifestEntries>
+            </archive>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-release-plugin</artifactId>
+          <version>${version.release.plugin}</version>
+          <configuration>
+            <preparationGoals>clean install</preparationGoals>
+            <autoVersionSubmodules>true</autoVersionSubmodules>
+            <tagNameFormat>@{project.version}</tagNameFormat>
+            <pushChanges>false</pushChanges>
+            <localCheckout>true</localCheckout>
+            <remoteTagging>false</remoteTagging>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.jsonschema2pojo</groupId>
+          <artifactId>jsonschema2pojo-maven-plugin</artifactId>
+          <version>${version.jsonschema2pojo-maven-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>${version.surefire.plugin}</version>
+          <configuration>
+            <argLine>-Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m</argLine>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-failsafe-plugin</artifactId>
+          <version>${version.failsafe.plugin}</version>
+          <configuration>
+            <argLine>-Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m</argLine>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-checkstyle-plugin</artifactId>
+          <version>${version.checkstyle.plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>com.coveo</groupId>
+          <artifactId>fmt-maven-plugin</artifactId>
+          <version>${version.fmt-maven-plugin}</version>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-jar-plugin</artifactId>
+          <version>${version.jar.plugin}</version>
+          <configuration>
+            <archive>
+              <index>true</index>
+              <manifest>
+                <addDefaultSpecificationEntries>
+                  true
+                </addDefaultSpecificationEntries>
+                <addDefaultImplementationEntries>
+                  true
+                </addDefaultImplementationEntries>
+              </manifest>
+              <manifestEntries>
+                <Implementation-URL>${project.url}</Implementation-URL>
+                <Java-Version>${java.version}</Java-Version>
+                <Java-Vendor>${java.vendor}</Java-Vendor>
+                <Os-Name>${os.name}</Os-Name>
+                <Os-Arch>${os.arch}</Os-Arch>
+                <Os-Version>${os.version}</Os-Version>
+                <Scm-Url>${project.scm.url}</Scm-Url>
+                <Scm-Connection>${project.scm.connection}</Scm-Connection>
+                <Scm-Revision>${buildNumber}</Scm-Revision>
+              </manifestEntries>
+            </archive>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-javadoc-plugin</artifactId>
+          <version>${version.javadoc.plugin}</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
 
-    <build>
+
+  <distributionManagement>
+    <snapshotRepository>
+      <id>ossrh</id>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+    </snapshotRepository>
+    <repository>
+      <id>ossrh</id>
+      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+    </repository>
+  </distributionManagement>
+
+  <pluginRepositories>
+    <pluginRepository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>https://repo.maven.apache.org/maven2</url>
+      <layout>default</layout>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <profiles>
+    <profile>
+      <id>release</id>
+      <build>
         <plugins>
-            <plugin>
-                <artifactId>maven-deploy-plugin</artifactId>
-                <version>${version.deploy.plugin}</version>
-                <configuration>
-                    <retryFailedDeploymentCount>10</retryFailedDeploymentCount>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-enforcer-plugin</artifactId>
-                <version>${version.enforcer.plugin}</version>
-                <executions>
-                    <execution>
-                        <id>enforce-versions</id>
-                        <goals>
-                            <goal>enforce</goal>
-                        </goals>
-                        <configuration>
-                            <rules>
-                                <requireMavenVersion>
-                                    <version>${version.maven}</version>
-                                </requireMavenVersion>
-                                <requireJavaVersion>
-                                    <version>${version.jdk}</version>
-                                </requireJavaVersion>
-                            </rules>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <version>${version.compiler.plugin}</version>
-                <configuration>
-                    <showDeprecation>true</showDeprecation>
-                    <showWarnings>true</showWarnings>
-                    <compilerArgs>
-                        <arg>-Xlint:unchecked</arg>
-                    </compilerArgs>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.jsonschema2pojo</groupId>
-                <artifactId>jsonschema2pojo-maven-plugin</artifactId>
-                <version>${version.jsonschema2pojo-maven-plugin}</version>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-surefire-plugin</artifactId>
-                <version>${version.surefire.plugin}</version>
-                <configuration>
-                    <argLine>-Xmx1024m -XX:+IgnoreUnrecognizedVMOptions -XX:MaxPermSize=256m</argLine>
-                </configuration>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-checkstyle-plugin</artifactId>
-                <version>${version.checkstyle.plugin}</version>
-            </plugin>
-            <plugin>
-                <groupId>com.coveo</groupId>
-                <artifactId>fmt-maven-plugin</artifactId>
-                <version>${version.fmt-maven-plugin}</version>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <version>${version.jar.plugin}</version>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-source-plugin</artifactId>
-                <version>3.0.1</version>
-                <executions>
-                    <execution>
-                        <id>attach-sources</id>
-                        <goals>
-                            <goal>jar</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-javadoc-plugin</artifactId>
-                <version>3.5.0</version>
-                <configuration>
-                    <source>8</source>
-                    <additionalparam>-Xdoclint:none</additionalparam>
-                </configuration>
-                <executions>
-                    <execution>
-                        <id>attach-javadocs</id>
-                        <goals>
-                            <goal>jar</goal>
-                        </goals>
-                        <configuration>
-                            <failOnError>false</failOnError>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-gpg-plugin</artifactId>
-                <version>1.6</version>
-                <executions>
-                    <execution>
-                        <id>sign-artifacts</id>
-                        <phase>verify</phase>
-                        <goals>
-                            <goal>sign</goal>
-                        </goals>
-                        <configuration>
-                            <gpgArguments>
-                                <arg>--batch</arg>
-                                <arg>--pinentry-mode</arg>
-                                <arg>loopback</arg>
-                            </gpgArguments>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <configuration>
+              <gpgArguments>
+                <arg>--pinentry-mode</arg>
+                <arg>loopback</arg>
+              </gpgArguments>
+            </configuration>
+            <executions>
+              <execution>
+                <id>sign-artifacts</id>
+                <phase>verify</phase>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <executions>
+              <execution>
+                <phase>package</phase>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
         </plugins>
-    </build>
-
-    <distributionManagement>
-        <snapshotRepository>
-            <id>ossrh</id>
-            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
-        </snapshotRepository>
-        <repository>
-            <id>ossrh</id>
-            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
-        </repository>
-    </distributionManagement>
+      </build>
+    </profile>
+  </profiles>
 
-    <pluginRepositories>
-        <pluginRepository>
-            <id>central</id>
-            <name>Central Repository</name>
-            <url>https://repo.maven.apache.org/maven2</url>
-            <layout>default</layout>
-            <snapshots>
-                <enabled>false</enabled>
-            </snapshots>
-        </pluginRepository>
-    </pluginRepositories>
 </project>
\ No newline at end of file
diff --git a/validation/pom.xml b/validation/pom.xml
index 57afbbb..6b4e808 100644
--- a/validation/pom.xml
+++ b/validation/pom.xml
@@ -34,12 +34,10 @@
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-lang3</artifactId>
         </dependency>
-
         <dependency>
-            <groupId>com.github.erosb</groupId>
-            <artifactId>everit-json-schema</artifactId>
+          <groupId>com.networknt</groupId>
+          <artifactId>json-schema-validator</artifactId>
         </dependency>
-
         <!-- test -->
         <dependency>
             <groupId>org.junit.jupiter</groupId>
diff --git a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java b/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
index abef046..12e4e91 100644
--- a/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
+++ b/validation/src/main/java/io/serverlessworkflow/validation/WorkflowValidatorImpl.java
@@ -15,8 +15,9 @@
  */
 package io.serverlessworkflow.validation;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.networknt.schema.JsonSchemaFactory;
+import com.networknt.schema.SpecVersion.VersionFlag;
 import io.serverlessworkflow.api.Workflow;
 import io.serverlessworkflow.api.actions.Action;
 import io.serverlessworkflow.api.events.EventDefinition;
@@ -27,15 +28,14 @@ import io.serverlessworkflow.api.interfaces.WorkflowValidator;
 import io.serverlessworkflow.api.states.*;
 import io.serverlessworkflow.api.switchconditions.DataCondition;
 import io.serverlessworkflow.api.switchconditions.EventCondition;
+import io.serverlessworkflow.api.utils.Utils;
 import io.serverlessworkflow.api.validation.ValidationError;
 import io.serverlessworkflow.api.validation.WorkflowSchemaLoader;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import org.everit.json.schema.Schema;
-import org.everit.json.schema.ValidationException;
-import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,7 +44,7 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
   private static final Logger logger = LoggerFactory.getLogger(WorkflowValidatorImpl.class);
   private boolean schemaValidationEnabled = true;
   private List<ValidationError> validationErrors = new ArrayList<>();
-  private Schema workflowSchema = WorkflowSchemaLoader.getWorkflowSchema();
+  private JsonNode workflowSchema = WorkflowSchemaLoader.getWorkflowSchema();
   private String source;
   private Workflow workflow;
 
@@ -66,34 +66,13 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
     if (workflow == null) {
       try {
         if (schemaValidationEnabled && source != null) {
-          try {
-            if (!source.trim().startsWith("{")) {
-              // convert yaml to json to validate
-              ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
-              Object obj = yamlReader.readValue(source, Object.class);
-
-              ObjectMapper jsonWriter = new ObjectMapper();
-
-              workflowSchema.validate(new JSONObject(jsonWriter.writeValueAsString(obj)));
-            } else {
-              workflowSchema.validate(new JSONObject(source));
-            }
-          } catch (ValidationException e) {
-            e.getCausingExceptions().stream()
-                .map(ValidationException::getMessage)
-                .forEach(
-                    m -> {
-                      if ((!m.equals("#/functions: expected type: JSONObject, found: JSONArray")
-                          && !m.equals("#/events: expected type: JSONObject, found: JSONArray")
-                          && !m.equals("#/start: expected type: JSONObject, found: String")
-                          && !m.equals("#/retries: expected type: JSONObject, found: JSONArray"))) {
-                        addValidationError(m, ValidationError.SCHEMA_VALIDATION);
-                      }
-                    });
-          }
+          JsonSchemaFactory.getInstance(VersionFlag.V7)
+              .getSchema(workflowSchema)
+              .validate(Utils.getNode(source))
+              .forEach(m -> addValidationError(m.getMessage(), ValidationError.SCHEMA_VALIDATION));
         }
-      } catch (Exception e) {
-        logger.error("Schema validation exception: " + e.getMessage());
+      } catch (IOException e) {
+        logger.error("Unexpected error during validation", e);
       }
     }
 
@@ -101,258 +80,244 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
     // there is no point of doing the workflow validation
     if (validationErrors.size() > 0) {
       return validationErrors;
-    } else {
-      if (workflow == null) {
-        workflow = Workflow.fromSource(source);
-      }
+    } else if (workflow == null) {
+      workflow = Workflow.fromSource(source);
+    }
 
-      List<FunctionDefinition> functions =
-          workflow.getFunctions() != null ? workflow.getFunctions().getFunctionDefs() : null;
+    List<FunctionDefinition> functions =
+        workflow.getFunctions() != null ? workflow.getFunctions().getFunctionDefs() : null;
 
-      List<EventDefinition> events =
-          workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;
+    List<EventDefinition> events =
+        workflow.getEvents() != null ? workflow.getEvents().getEventDefs() : null;
 
-      if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
-          && (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
-        addValidationError(
-            "Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
-      }
+    if ((workflow.getId() == null || workflow.getId().trim().isEmpty())
+        && (workflow.getKey() == null || workflow.getKey().trim().isEmpty())) {
+      addValidationError(
+          "Workflow id or key should not be empty", ValidationError.WORKFLOW_VALIDATION);
+    }
 
-      if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {
-        addValidationError(
-            "Workflow version should not be empty", ValidationError.WORKFLOW_VALIDATION);
-      }
+    if (workflow.getVersion() == null || workflow.getVersion().trim().isEmpty()) {
+      addValidationError(
+          "Workflow version should not be empty", ValidationError.WORKFLOW_VALIDATION);
+    }
 
-      if (workflow.getStates() == null || workflow.getStates().isEmpty()) {
-        addValidationError("No states found", ValidationError.WORKFLOW_VALIDATION);
-      }
+    if (workflow.getStates() == null || workflow.getStates().isEmpty()) {
+      addValidationError("No states found", ValidationError.WORKFLOW_VALIDATION);
+    }
 
-      if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
-        boolean existingStateWithStartProperty = false;
-        if (workflow.getStart() != null) {
-          String startProperty = workflow.getStart().getStateName();
-          for (State s : workflow.getStates()) {
-            if (s.getName().equals(startProperty)) {
-              existingStateWithStartProperty = true;
-              break;
-            }
+    if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
+      boolean existingStateWithStartProperty = false;
+      if (workflow.getStart() != null) {
+        String startProperty = workflow.getStart().getStateName();
+        for (State s : workflow.getStates()) {
+          if (s.getName().equals(startProperty)) {
+            existingStateWithStartProperty = true;
+            break;
           }
-        } else {
-          existingStateWithStartProperty = true;
-        }
-        if (!existingStateWithStartProperty) {
-          addValidationError(
-              "No state name found that matches the workflow start definition",
-              ValidationError.WORKFLOW_VALIDATION);
         }
+      } else {
+        existingStateWithStartProperty = true;
       }
+      if (!existingStateWithStartProperty) {
+        addValidationError(
+            "No state name found that matches the workflow start definition",
+            ValidationError.WORKFLOW_VALIDATION);
+      }
+    }
 
-      Validation validation = new Validation();
-      if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
-        workflow
-            .getStates()
-            .forEach(
-                s -> {
-                  if (s.getName() != null && s.getName().trim().isEmpty()) {
-                    addValidationError(
-                        "State name should not be empty", ValidationError.WORKFLOW_VALIDATION);
-                  } else {
-                    validation.addState(s.getName());
-                  }
-
-                  if (s.getEnd() != null) {
-                    validation.addEndState();
-                  }
-
-                  if (s instanceof OperationState) {
-                    OperationState operationState = (OperationState) s;
-
-                    List<Action> actions = operationState.getActions();
-                    for (Action action : actions) {
-                      if (action.getFunctionRef() != null) {
-                        if (action.getFunctionRef().getRefName().isEmpty()) {
-                          addValidationError(
-                              "Operation State action functionRef should not be null or empty",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
-
-                        if (!haveFunctionDefinition(
-                            action.getFunctionRef().getRefName(), functions)) {
-                          addValidationError(
-                              "Operation State action functionRef does not reference an existing workflow function definition",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
+    Validation validation = new Validation();
+    if (workflow.getStates() != null && !workflow.getStates().isEmpty()) {
+      workflow
+          .getStates()
+          .forEach(
+              s -> {
+                if (s.getName() != null && s.getName().trim().isEmpty()) {
+                  addValidationError(
+                      "State name should not be empty", ValidationError.WORKFLOW_VALIDATION);
+                } else {
+                  validation.addState(s.getName());
+                }
+
+                if (s.getEnd() != null) {
+                  validation.addEndState();
+                }
+
+                if (s instanceof OperationState) {
+                  OperationState operationState = (OperationState) s;
+
+                  List<Action> actions = operationState.getActions();
+                  for (Action action : actions) {
+                    if (action.getFunctionRef() != null) {
+                      if (action.getFunctionRef().getRefName().isEmpty()) {
+                        addValidationError(
+                            "Operation State action functionRef should not be null or empty",
+                            ValidationError.WORKFLOW_VALIDATION);
                       }
 
-                      if (action.getEventRef() != null) {
-                        if (action.getEventRef().getTriggerEventRef().isEmpty()) {
-                          addValidationError(
-                              "Operation State action trigger eventRef does not reference an existing workflow event definition",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
-
-                        if (action.getEventRef().getResultEventRef().isEmpty()) {
-                          addValidationError(
-                              "Operation State action results eventRef does not reference an existing workflow event definition",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
-
-                        if (!haveEventsDefinition(
-                            action.getEventRef().getTriggerEventRef(), events)) {
-                          addValidationError(
-                              "Operation State action trigger event def does not reference an existing workflow event definition",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
-
-                        if (!haveEventsDefinition(
-                            action.getEventRef().getResultEventRef(), events)) {
-                          addValidationError(
-                              "Operation State action results event def does not reference an existing workflow event definition",
-                              ValidationError.WORKFLOW_VALIDATION);
-                        }
+                      if (!haveFunctionDefinition(
+                          action.getFunctionRef().getRefName(), functions)) {
+                        addValidationError(
+                            "Operation State action functionRef does not reference an existing workflow function definition",
+                            ValidationError.WORKFLOW_VALIDATION);
                       }
                     }
-                  }
 
-                  if (s instanceof EventState) {
-                    EventState eventState = (EventState) s;
-                    if (eventState.getOnEvents() == null || eventState.getOnEvents().size() < 1) {
-                      addValidationError(
-                          "Event State has no eventActions defined",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
-                    List<OnEvents> eventsActionsList = eventState.getOnEvents();
-                    for (OnEvents onEvents : eventsActionsList) {
+                    if (action.getEventRef() != null) {
 
-                      List<String> eventRefs = onEvents.getEventRefs();
-                      if (eventRefs == null || eventRefs.size() < 1) {
+                      if (!haveEventsDefinition(
+                          action.getEventRef().getTriggerEventRef(), events)) {
                         addValidationError(
-                            "Event State eventsActions has no event refs",
+                            "Operation State action trigger event def does not reference an existing workflow event definition",
+                            ValidationError.WORKFLOW_VALIDATION);
+                      }
+
+                      if (!haveEventsDefinition(action.getEventRef().getResultEventRef(), events)) {
+                        addValidationError(
+                            "Operation State action results event def does not reference an existing workflow event definition",
                             ValidationError.WORKFLOW_VALIDATION);
-                      } else {
-                        for (String eventRef : eventRefs) {
-                          if (!haveEventsDefinition(eventRef, events)) {
-                            addValidationError(
-                                "Event State eventsActions eventRef does not match a declared workflow event definition",
-                                ValidationError.WORKFLOW_VALIDATION);
-                          }
-                        }
                       }
                     }
                   }
+                }
 
-                  if (s instanceof SwitchState) {
-                    SwitchState switchState = (SwitchState) s;
-                    if ((switchState.getDataConditions() == null
-                            || switchState.getDataConditions().size() < 1)
-                        && (switchState.getEventConditions() == null
-                            || switchState.getEventConditions().size() < 1)) {
-                      addValidationError(
-                          "Switch state should define either data or event conditions",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                if (s instanceof EventState) {
+                  EventState eventState = (EventState) s;
+                  if (eventState.getOnEvents() == null || eventState.getOnEvents().size() < 1) {
+                    addValidationError(
+                        "Event State has no eventActions defined",
+                        ValidationError.WORKFLOW_VALIDATION);
+                  }
+                  List<OnEvents> eventsActionsList = eventState.getOnEvents();
+                  for (OnEvents onEvents : eventsActionsList) {
 
-                    if (switchState.getDefaultCondition() == null) {
+                    List<String> eventRefs = onEvents.getEventRefs();
+                    if (eventRefs == null || eventRefs.size() < 1) {
                       addValidationError(
-                          "Switch state should define a default transition",
+                          "Event State eventsActions has no event refs",
                           ValidationError.WORKFLOW_VALIDATION);
-                    }
-
-                    if (switchState.getEventConditions() != null
-                        && switchState.getEventConditions().size() > 0) {
-                      List<EventCondition> eventConditions = switchState.getEventConditions();
-                      for (EventCondition ec : eventConditions) {
-                        if (!haveEventsDefinition(ec.getEventRef(), events)) {
+                    } else {
+                      for (String eventRef : eventRefs) {
+                        if (!haveEventsDefinition(eventRef, events)) {
                           addValidationError(
-                              "Switch state event condition eventRef does not reference a defined workflow event",
+                              "Event State eventsActions eventRef does not match a declared workflow event definition",
                               ValidationError.WORKFLOW_VALIDATION);
                         }
-                        if (ec.getEnd() != null) {
-                          validation.addEndState();
-                        }
                       }
                     }
+                  }
+                }
+
+                if (s instanceof SwitchState) {
+                  SwitchState switchState = (SwitchState) s;
+                  if ((switchState.getDataConditions() == null
+                          || switchState.getDataConditions().size() < 1)
+                      && (switchState.getEventConditions() == null
+                          || switchState.getEventConditions().size() < 1)) {
+                    addValidationError(
+                        "Switch state should define either data or event conditions",
+                        ValidationError.WORKFLOW_VALIDATION);
+                  }
 
-                    if (switchState.getDataConditions() != null
-                        && switchState.getDataConditions().size() > 0) {
-                      List<DataCondition> dataConditions = switchState.getDataConditions();
-                      for (DataCondition dc : dataConditions) {
-                        if (dc.getEnd() != null) {
-                          validation.addEndState();
-                        }
+                  if (switchState.getDefaultCondition() == null) {
+                    addValidationError(
+                        "Switch state should define a default transition",
+                        ValidationError.WORKFLOW_VALIDATION);
+                  }
+
+                  if (switchState.getEventConditions() != null
+                      && switchState.getEventConditions().size() > 0) {
+                    List<EventCondition> eventConditions = switchState.getEventConditions();
+                    for (EventCondition ec : eventConditions) {
+                      if (!haveEventsDefinition(ec.getEventRef(), events)) {
+                        addValidationError(
+                            "Switch state event condition eventRef does not reference a defined workflow event",
+                            ValidationError.WORKFLOW_VALIDATION);
+                      }
+                      if (ec.getEnd() != null) {
+                        validation.addEndState();
                       }
                     }
                   }
 
-                  if (s instanceof SleepState) {
-                    SleepState sleepState = (SleepState) s;
-                    if (sleepState.getDuration() == null || sleepState.getDuration().length() < 1) {
-                      addValidationError(
-                          "Sleep state should have a non-empty time delay",
-                          ValidationError.WORKFLOW_VALIDATION);
+                  if (switchState.getDataConditions() != null
+                      && switchState.getDataConditions().size() > 0) {
+                    List<DataCondition> dataConditions = switchState.getDataConditions();
+                    for (DataCondition dc : dataConditions) {
+                      if (dc.getEnd() != null) {
+                        validation.addEndState();
+                      }
                     }
                   }
+                }
+
+                if (s instanceof SleepState) {
+                  SleepState sleepState = (SleepState) s;
+                  if (sleepState.getDuration() == null || sleepState.getDuration().length() < 1) {
+                    addValidationError(
+                        "Sleep state should have a non-empty time delay",
+                        ValidationError.WORKFLOW_VALIDATION);
+                  }
+                }
 
-                  if (s instanceof ParallelState) {
-                    ParallelState parallelState = (ParallelState) s;
+                if (s instanceof ParallelState) {
+                  ParallelState parallelState = (ParallelState) s;
 
-                    if (parallelState.getBranches() == null
-                        || parallelState.getBranches().size() < 2) {
-                      addValidationError(
-                          "Parallel state should have at lest two branches",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                  if (parallelState.getBranches() == null
+                      || parallelState.getBranches().size() < 2) {
+                    addValidationError(
+                        "Parallel state should have at lest two branches",
+                        ValidationError.WORKFLOW_VALIDATION);
                   }
+                }
 
-                  if (s instanceof InjectState) {
-                    InjectState injectState = (InjectState) s;
-                    if (injectState.getData() == null || injectState.getData().isEmpty()) {
-                      addValidationError(
-                          "InjectState should have non-null data",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                if (s instanceof InjectState) {
+                  InjectState injectState = (InjectState) s;
+                  if (injectState.getData() == null || injectState.getData().isEmpty()) {
+                    addValidationError(
+                        "InjectState should have non-null data",
+                        ValidationError.WORKFLOW_VALIDATION);
                   }
+                }
 
-                  if (s instanceof ForEachState) {
-                    ForEachState forEachState = (ForEachState) s;
-                    if (forEachState.getInputCollection() == null
-                        || forEachState.getInputCollection().isEmpty()) {
-                      addValidationError(
-                          "ForEach state should have a valid inputCollection",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                if (s instanceof ForEachState) {
+                  ForEachState forEachState = (ForEachState) s;
+                  if (forEachState.getInputCollection() == null
+                      || forEachState.getInputCollection().isEmpty()) {
+                    addValidationError(
+                        "ForEach state should have a valid inputCollection",
+                        ValidationError.WORKFLOW_VALIDATION);
                   }
+                }
 
-                  if (s instanceof CallbackState) {
-                    CallbackState callbackState = (CallbackState) s;
+                if (s instanceof CallbackState) {
+                  CallbackState callbackState = (CallbackState) s;
 
-                    if (!haveEventsDefinition(callbackState.getEventRef(), events)) {
-                      addValidationError(
-                          "CallbackState event ref does not reference a defined workflow event definition",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                  if (!haveEventsDefinition(callbackState.getEventRef(), events)) {
+                    addValidationError(
+                        "CallbackState event ref does not reference a defined workflow event definition",
+                        ValidationError.WORKFLOW_VALIDATION);
+                  }
 
-                    if (!haveFunctionDefinition(
-                        callbackState.getAction().getFunctionRef().getRefName(), functions)) {
-                      addValidationError(
-                          "CallbackState action function ref does not reference a defined workflow function definition",
-                          ValidationError.WORKFLOW_VALIDATION);
-                    }
+                  if (!haveFunctionDefinition(
+                      callbackState.getAction().getFunctionRef().getRefName(), functions)) {
+                    addValidationError(
+                        "CallbackState action function ref does not reference a defined workflow function definition",
+                        ValidationError.WORKFLOW_VALIDATION);
                   }
-                });
+                }
+              });
 
-        if (validation.endStates == 0) {
-          addValidationError("No end state found.", ValidationError.WORKFLOW_VALIDATION);
-        }
+      if (validation.endStates == 0) {
+        addValidationError("No end state found.", ValidationError.WORKFLOW_VALIDATION);
       }
-
-      return validationErrors;
     }
+
+    return validationErrors;
   }
 
   @Override
   public boolean isValid() {
-    return validate().size() < 1;
+    return validate().isEmpty();
   }
 
   @Override
@@ -381,17 +346,30 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
   }
 
   private boolean haveEventsDefinition(String eventName, List<EventDefinition> events) {
+    if (eventName == null) {
+      return true;
+    }
     if (events != null) {
       EventDefinition eve =
           events.stream().filter(e -> e.getName().equals(eventName)).findFirst().orElse(null);
-
       return eve == null ? false : true;
     } else {
       return false;
     }
   }
 
+  private static final Set<String> skipMessages =
+      new HashSet<String>() {
+        {
+          add("$.start: string found, object expected");
+          add("$.functions: array found, object expected");
+        }
+      };
+
   private void addValidationError(String message, String type) {
+    if (skipMessages.contains(message)) {
+      return;
+    }
     ValidationError mainError = new ValidationError();
     mainError.setMessage(message);
     mainError.setType(type);
@@ -399,30 +377,9 @@ public class WorkflowValidatorImpl implements WorkflowValidator {
   }
 
   private class Validation {
-
-    final Set<String> events = new HashSet<>();
-    final Set<String> functions = new HashSet<>();
     final Set<String> states = new HashSet<>();
     Integer endStates = 0;
 
-    void addFunction(String name) {
-      if (functions.contains(name)) {
-        addValidationError(
-            "Function does not have an unique name: " + name, ValidationError.WORKFLOW_VALIDATION);
-      } else {
-        functions.add(name);
-      }
-    }
-
-    void addEvent(String name) {
-      if (events.contains(name)) {
-        addValidationError(
-            "Event does not have an unique name: " + name, ValidationError.WORKFLOW_VALIDATION);
-      } else {
-        events.add(name);
-      }
-    }
-
     void addState(String name) {
       if (states.contains(name)) {
         addValidationError(


Test patch:
diff --git a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java b/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
index a1854d4..f5b30d0 100644
--- a/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
+++ b/api/src/test/java/io/serverlessworkflow/api/test/MarkupToWorkflowTest.java
@@ -44,6 +44,7 @@ import io.serverlessworkflow.api.workflow.Events;
 import io.serverlessworkflow.api.workflow.Retries;
 import io.serverlessworkflow.api.workflow.Secrets;
 import java.util.List;
+import java.util.Map;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.ValueSource;
 
@@ -264,6 +265,12 @@ public class MarkupToWorkflowTest {
     assertEquals("RejectApplication", cond2.getTransition().getNextState());
     assertNotNull(cond2.getTransition().getProduceEvents());
     assertEquals(1, cond2.getTransition().getProduceEvents().size());
+    assertNotNull(cond2.getTransition().getProduceEvents().get(0).getContextAttributes());
+    Map<String, String> contextAttributes =
+        cond2.getTransition().getProduceEvents().get(0).getContextAttributes();
+    assertEquals(2, contextAttributes.size());
+    assertEquals("IN", contextAttributes.get("order_location"));
+    assertEquals("online", contextAttributes.get("order_type"));
     assertFalse(cond2.getTransition().isCompensate());
 
     assertNotNull(switchState.getDefaultCondition());
diff --git a/api/src/test/resources/features/transitions.json b/api/src/test/resources/features/transitions.json
index cacc94a..ed7b762 100644
--- a/api/src/test/resources/features/transitions.json
+++ b/api/src/test/resources/features/transitions.json
@@ -23,7 +23,11 @@
             "produceEvents": [
               {
                 "eventRef": "provisioningCompleteEvent",
-                "data": "${ .provisionedOrders }"
+                "data": "${ .provisionedOrders }",
+                "contextAttributes": {
+                  "order_location": "IN",
+                  "order_type": "online"
+                }
               }
             ]
           }
diff --git a/api/src/test/resources/features/transitions.yml b/api/src/test/resources/features/transitions.yml
index 1b89a85..3ec34ae 100644
--- a/api/src/test/resources/features/transitions.yml
+++ b/api/src/test/resources/features/transitions.yml
@@ -18,6 +18,9 @@ states:
           produceEvents:
             - eventRef: provisioningCompleteEvent
               data: "${ .provisionedOrders }"
+              contextAttributes:
+                "order_location": "IN"
+                "order_type": "online"
     defaultCondition:
       transition:
         nextState: RejectApplication
diff --git a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java b/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
index a81e14f..0823752 100644
--- a/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
+++ b/validation/src/test/java/io/serverlessworkflow/validation/test/WorkflowValidationTest.java
@@ -15,14 +15,26 @@
  */
 package io.serverlessworkflow.validation.test;
 
+import static io.serverlessworkflow.api.states.DefaultState.Type.OPERATION;
 import static io.serverlessworkflow.api.states.DefaultState.Type.SLEEP;
 
 import io.serverlessworkflow.api.Workflow;
+import io.serverlessworkflow.api.actions.Action;
 import io.serverlessworkflow.api.end.End;
+import io.serverlessworkflow.api.events.EventDefinition;
+import io.serverlessworkflow.api.events.EventRef;
+import io.serverlessworkflow.api.functions.FunctionDefinition;
+import io.serverlessworkflow.api.functions.FunctionDefinition.Type;
+import io.serverlessworkflow.api.functions.FunctionRef;
 import io.serverlessworkflow.api.interfaces.WorkflowValidator;
+import io.serverlessworkflow.api.retry.RetryDefinition;
 import io.serverlessworkflow.api.start.Start;
+import io.serverlessworkflow.api.states.OperationState;
 import io.serverlessworkflow.api.states.SleepState;
 import io.serverlessworkflow.api.validation.ValidationError;
+import io.serverlessworkflow.api.workflow.Events;
+import io.serverlessworkflow.api.workflow.Functions;
+import io.serverlessworkflow.api.workflow.Retries;
 import io.serverlessworkflow.validation.WorkflowValidatorImpl;
 import java.util.Arrays;
 import java.util.List;
@@ -46,8 +58,7 @@ public class WorkflowValidationTest {
     List<ValidationError> validationErrors =
         workflowValidator.setSource("---\n" + "key: abc\n").validate();
     Assertions.assertNotNull(validationErrors);
-    System.out.println(validationErrors);
-    Assertions.assertEquals(3, validationErrors.size());
+    Assertions.assertEquals(4, validationErrors.size());
   }
 
   @Test
@@ -108,11 +119,10 @@ public class WorkflowValidationTest {
                     + "}")
             .validate();
     Assertions.assertNotNull(validationErrors);
-    Assertions.assertEquals(2, validationErrors.size());
+    Assertions.assertEquals(1, validationErrors.size());
 
     Assertions.assertEquals(
-        "Workflow id or key should not be empty", validationErrors.get(0).getMessage());
-    Assertions.assertEquals("No states found", validationErrors.get(1).getMessage());
+        "$.id: is missing but it is required", validationErrors.get(0).getMessage());
   }
 
   @Test
@@ -162,7 +172,6 @@ public class WorkflowValidationTest {
     Assertions.assertNotNull(validationErrors);
     Assertions.assertEquals(1, validationErrors.size());
 
-    // validationErrors.stream().forEach(v -> System.out.println(v.toString()));
     Assertions.assertEquals(
         "Operation State action functionRef does not reference an existing workflow function definition",
         validationErrors.get(0).getMessage());
@@ -280,4 +289,48 @@ public class WorkflowValidationTest {
         "CallbackState action function ref does not reference a defined workflow function definition",
         validationErrors.get(1).getMessage());
   }
+
+  @Test
+  void testFunctionCall() {
+    Workflow workflow =
+        new Workflow()
+            .withId("test-workflow")
+            .withVersion("1.0")
+            .withStart(new Start().withStateName("start"))
+            .withFunctions(
+                new Functions(
+                    Arrays.asList(new FunctionDefinition("expression").withType(Type.EXPRESSION))))
+            .withStates(
+                Arrays.asList(
+                    new OperationState()
+                        .withName("start")
+                        .withType(OPERATION)
+                        .withActions(
+                            Arrays.asList(
+                                new Action().withFunctionRef(new FunctionRef("expression"))))
+                        .withEnd(new End())));
+    Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty());
+  }
+
+  @Test
+  void testEventCall() {
+    Workflow workflow =
+        new Workflow()
+            .withId("test-workflow")
+            .withVersion("1.0")
+            .withStart(new Start().withStateName("start"))
+            .withEvents(new Events(Arrays.asList(new EventDefinition().withName("event"))))
+            .withRetries(new Retries(Arrays.asList(new RetryDefinition("start", "PT1S"))))
+            .withStates(
+                Arrays.asList(
+                    new OperationState()
+                        .withName("start")
+                        .withType(OPERATION)
+                        .withActions(
+                            Arrays.asList(
+                                new Action()
+                                    .withEventRef(new EventRef().withTriggerEventRef("event"))))
+                        .withEnd(new End())));
+    Assertions.assertTrue(new WorkflowValidatorImpl().setWorkflow(workflow).validate().isEmpty());
+  }
 }