[Hotfix][Core] Fix the NullPointException for the json config of the job without pluginname (#6815)

diff --git a/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/FlinkCommandArgsTest.java b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/FlinkCommandArgsTest.java
new file mode 100644
index 0000000..050a1a2
--- /dev/null
+++ b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/FlinkCommandArgsTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.seatunnel.core.starter.flink;
+
+import org.apache.seatunnel.shade.com.typesafe.config.ConfigException;
+
+import org.apache.seatunnel.core.starter.SeaTunnel;
+import org.apache.seatunnel.core.starter.flink.args.FlinkCommandArgs;
+import org.apache.seatunnel.core.starter.flink.multitable.MultiTableSinkTest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+
+import static org.apache.seatunnel.api.common.CommonOptions.PLUGIN_NAME;
+
+public class FlinkCommandArgsTest {
+    @Test
+    public void testExecuteClientCommandArgsWithPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        FlinkCommandArgs flinkCommandArgs = buildFlinkCommandArgs(configFile);
+        Assertions.assertDoesNotThrow(() -> SeaTunnel.run(flinkCommandArgs.buildCommand()));
+    }
+
+    @Test
+    public void testExecuteClientCommandArgsWithoutPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory_without_pluginname.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        FlinkCommandArgs flinkCommandArgs = buildFlinkCommandArgs(configFile);
+        ConfigException configException =
+                Assertions.assertThrows(
+                        ConfigException.class,
+                        () -> SeaTunnel.run(flinkCommandArgs.buildCommand()));
+        Assertions.assertEquals(
+                String.format("No configuration setting found for key '%s'", PLUGIN_NAME.key()),
+                configException.getMessage());
+    }
+
+    private static FlinkCommandArgs buildFlinkCommandArgs(String configFile) {
+        FlinkCommandArgs flinkCommandArgs = new FlinkCommandArgs();
+        flinkCommandArgs.setConfigFile(configFile);
+        flinkCommandArgs.setCheckConfig(false);
+        flinkCommandArgs.setVariables(null);
+        return flinkCommandArgs;
+    }
+}
diff --git a/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/multitable/MultiTableSinkTest.java b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/multitable/MultiTableSinkTest.java
index 6ca59d8..1cd1787 100644
--- a/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/multitable/MultiTableSinkTest.java
+++ b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/java/org/apache/seatunnel/core/starter/flink/multitable/MultiTableSinkTest.java
@@ -24,6 +24,7 @@
 import org.apache.seatunnel.e2e.sink.inmemory.InMemorySinkWriter;
 
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
 
 import java.io.FileNotFoundException;
@@ -34,6 +35,7 @@
 import java.util.Collections;
 import java.util.List;
 
+@Order(1)
 public class MultiTableSinkTest {
 
     @Test
diff --git a/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory.json b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory.json
new file mode 100644
index 0000000..28b79bf
--- /dev/null
+++ b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory.json
@@ -0,0 +1,28 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH"
+  },
+  "source": [
+    {
+      "plugin_name": "FakeSource",
+      "result_table_name": "fake_to_inmemory_wtih_flink",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "plugin_name": "InMemory",
+      "source_table_name": "fake_to_inmemory_wtih_flink"
+    }
+  ]
+}
diff --git a/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
new file mode 100644
index 0000000..f35ee0c
--- /dev/null
+++ b/seatunnel-core/seatunnel-flink-starter/seatunnel-flink-15-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
@@ -0,0 +1,26 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH"
+  },
+  "source": [
+    {
+      "result_table_name": "fake_to_inmemory_wtih_flink",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "source_table_name": "fake_to_inmemory_wtih_flink"
+    }
+  ]
+}
diff --git a/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/SparkCommandArgsTest.java b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/SparkCommandArgsTest.java
new file mode 100644
index 0000000..da997e3
--- /dev/null
+++ b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/SparkCommandArgsTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.seatunnel.core.starter.spark;
+
+import org.apache.seatunnel.common.config.DeployMode;
+import org.apache.seatunnel.core.starter.SeaTunnel;
+import org.apache.seatunnel.core.starter.exception.CommandExecuteException;
+import org.apache.seatunnel.core.starter.spark.args.SparkCommandArgs;
+import org.apache.seatunnel.core.starter.spark.multitable.MultiTableSinkTest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnJre;
+import org.junit.jupiter.api.condition.JRE;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+
+import static org.apache.seatunnel.api.common.CommonOptions.PLUGIN_NAME;
+
+@DisabledOnJre(
+        value = JRE.JAVA_11,
+        disabledReason =
+                "We should update apache common lang3 version to 3.8 to avoid NPE, "
+                        + "see https://github.com/apache/commons-lang/commit/50ce8c44e1601acffa39f5568f0fc140aade0564")
+public class SparkCommandArgsTest {
+    @Test
+    public void testExecuteClientCommandArgsWithPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        SparkCommandArgs sparkCommandArgs = buildSparkCommands(configFile);
+        sparkCommandArgs.setDeployMode(DeployMode.CLIENT);
+        Assertions.assertDoesNotThrow(() -> SeaTunnel.run(sparkCommandArgs.buildCommand()));
+    }
+
+    @Test
+    public void testExecuteClientCommandArgsWithoutPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory_without_pluginname.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        SparkCommandArgs sparkCommandArgs = buildSparkCommands(configFile);
+        sparkCommandArgs.setDeployMode(DeployMode.CLIENT);
+        CommandExecuteException commandExecuteException =
+                Assertions.assertThrows(
+                        CommandExecuteException.class,
+                        () -> SeaTunnel.run(sparkCommandArgs.buildCommand()));
+        Assertions.assertEquals(
+                String.format("No configuration setting found for key '%s'", PLUGIN_NAME.key()),
+                commandExecuteException.getCause().getMessage());
+    }
+
+    private static SparkCommandArgs buildSparkCommands(String configFile) {
+        SparkCommandArgs sparkCommandArgs = new SparkCommandArgs();
+        sparkCommandArgs.setConfigFile(configFile);
+        sparkCommandArgs.setCheckConfig(false);
+        sparkCommandArgs.setVariables(null);
+        sparkCommandArgs.setDeployMode(DeployMode.CLIENT);
+        return sparkCommandArgs;
+    }
+}
diff --git a/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/multitable/MultiTableSinkTest.java b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/multitable/MultiTableSinkTest.java
index 15b9810..61ed445 100644
--- a/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/multitable/MultiTableSinkTest.java
+++ b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/java/org/apache/seatunnel/core/starter/spark/multitable/MultiTableSinkTest.java
@@ -25,6 +25,7 @@
 import org.apache.seatunnel.e2e.sink.inmemory.InMemorySinkWriter;
 
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledOnJre;
 import org.junit.jupiter.api.condition.JRE;
@@ -40,6 +41,7 @@
 import java.util.List;
 
 @Slf4j
+@Order(1)
 public class MultiTableSinkTest {
 
     @Test
diff --git a/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory.json b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory.json
new file mode 100644
index 0000000..88da70a
--- /dev/null
+++ b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory.json
@@ -0,0 +1,32 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH",
+    "spark.executor.instances": 1,
+    "spark.executor.cores": 1,
+    "spark.executor.memory": "1g",
+    "spark.master": "local"
+  },
+  "source": [
+    {
+      "plugin_name": "FakeSource",
+      "result_table_name": "fake_to_inmemory_wtih_spark",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "plugin_name": "InMemory",
+      "source_table_name": "fake_to_inmemory_wtih_spark"
+    }
+  ]
+}
diff --git a/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
new file mode 100644
index 0000000..ed6d930
--- /dev/null
+++ b/seatunnel-core/seatunnel-spark-starter/seatunnel-spark-3-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
@@ -0,0 +1,30 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH",
+    "spark.executor.instances": 1,
+    "spark.executor.cores": 1,
+    "spark.executor.memory": "1g",
+    "spark.master": "local"
+  },
+  "source": [
+    {
+      "result_table_name": "fake_to_inmemory_wtih_spark",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "source_table_name": "fake_to_inmemory_wtih_spark"
+    }
+  ]
+}
diff --git a/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/args/ClientCommandArgsTest.java b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/args/ClientCommandArgsTest.java
new file mode 100644
index 0000000..87d4aa5
--- /dev/null
+++ b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/args/ClientCommandArgsTest.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.seatunnel.core.starter.seatunnel.args;
+
+import org.apache.seatunnel.core.starter.SeaTunnel;
+import org.apache.seatunnel.core.starter.enums.MasterType;
+import org.apache.seatunnel.core.starter.exception.CommandExecuteException;
+import org.apache.seatunnel.core.starter.seatunnel.multitable.MultiTableSinkTest;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+
+import static org.apache.seatunnel.api.common.CommonOptions.PLUGIN_NAME;
+
+public class ClientCommandArgsTest {
+    @Test
+    public void testExecuteClientCommandArgsWithPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        ClientCommandArgs clientCommandArgs = buildClientCommandArgs(configFile);
+        Assertions.assertDoesNotThrow(() -> SeaTunnel.run(clientCommandArgs.buildCommand()));
+    }
+
+    @Test
+    public void testExecuteClientCommandArgsWithoutPluginName()
+            throws FileNotFoundException, URISyntaxException {
+        String configurePath = "/config/fake_to_inmemory_without_pluginname.json";
+        String configFile = MultiTableSinkTest.getTestConfigFile(configurePath);
+        ClientCommandArgs clientCommandArgs = buildClientCommandArgs(configFile);
+        CommandExecuteException commandExecuteException =
+                Assertions.assertThrows(
+                        CommandExecuteException.class,
+                        () -> SeaTunnel.run(clientCommandArgs.buildCommand()));
+        Assertions.assertEquals(
+                String.format(
+                        "The '%s' option is not configured, please configure it.",
+                        PLUGIN_NAME.key()),
+                commandExecuteException.getCause().getMessage());
+    }
+
+    private static ClientCommandArgs buildClientCommandArgs(String configFile) {
+        ClientCommandArgs clientCommandArgs = new ClientCommandArgs();
+        clientCommandArgs.setVariables(new ArrayList<>());
+        clientCommandArgs.setConfigFile(configFile);
+        clientCommandArgs.setMasterType(MasterType.LOCAL);
+        clientCommandArgs.setCheckConfig(false);
+        return clientCommandArgs;
+    }
+}
diff --git a/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/multitable/MultiTableSinkTest.java b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/multitable/MultiTableSinkTest.java
index e5c59b7..a542964 100644
--- a/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/multitable/MultiTableSinkTest.java
+++ b/seatunnel-core/seatunnel-starter/src/test/java/org/apache/seatunnel/core/starter/seatunnel/multitable/MultiTableSinkTest.java
@@ -25,6 +25,7 @@
 import org.apache.seatunnel.e2e.sink.inmemory.InMemorySinkWriter;
 
 import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Order;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledOnOs;
 import org.junit.jupiter.api.condition.OS;
@@ -37,6 +38,7 @@
 import java.util.Collections;
 import java.util.List;
 
+@Order(1)
 public class MultiTableSinkTest {
 
     @Test
diff --git a/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory.json b/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory.json
new file mode 100644
index 0000000..f380a6c
--- /dev/null
+++ b/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory.json
@@ -0,0 +1,28 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH"
+  },
+  "source": [
+    {
+      "plugin_name": "FakeSource",
+      "result_table_name": "fake_to_inmemory_wtih_zeta",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "plugin_name": "InMemory",
+      "source_table_name": "fake_to_inmemory_wtih_zeta"
+    }
+  ]
+}
diff --git a/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json b/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
new file mode 100644
index 0000000..bdf7c9d
--- /dev/null
+++ b/seatunnel-core/seatunnel-starter/src/test/resources/config/fake_to_inmemory_without_pluginname.json
@@ -0,0 +1,26 @@
+{
+  "env": {
+    "parallelism": 4,
+    "job.mode": "BATCH"
+  },
+  "source": [
+    {
+      "result_table_name": "fake_to_inmemory_wtih_zeta",
+      "row.num": 10,
+      "schema": {
+        "fields": {
+          "name": "string",
+          "age": "int",
+          "card": "int"
+        }
+      }
+    }
+  ],
+  "transform": [
+  ],
+  "sink": [
+    {
+      "source_table_name": "fake_to_inmemory_wtih_zeta"
+    }
+  ]
+}
diff --git a/seatunnel-e2e/seatunnel-e2e-common/src/test/resources/junit-platform.properties b/seatunnel-e2e/seatunnel-e2e-common/src/test/resources/junit-platform.properties
new file mode 100644
index 0000000..a9c2b88
--- /dev/null
+++ b/seatunnel-e2e/seatunnel-e2e-common/src/test/resources/junit-platform.properties
@@ -0,0 +1,20 @@
+################################################################################
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+################################################################################
+
+# We can use the following to order the test classes
+junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$OrderAnnotation
diff --git a/seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/parse/ConfigParserUtil.java b/seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/parse/ConfigParserUtil.java
index 9482297..377609a 100644
--- a/seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/parse/ConfigParserUtil.java
+++ b/seatunnel-engine/seatunnel-engine-core/src/main/java/org/apache/seatunnel/engine/core/parse/ConfigParserUtil.java
@@ -26,6 +26,7 @@
 import org.apache.seatunnel.engine.common.exception.JobDefineCheckException;
 
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import lombok.extern.slf4j.Slf4j;
 import scala.Tuple2;
@@ -263,7 +264,14 @@
     }
 
     public static String getFactoryId(ReadonlyConfig readonlyConfig) {
-        return readonlyConfig.get(PLUGIN_NAME);
+        String pluginName = readonlyConfig.get(PLUGIN_NAME);
+        if (StringUtils.isBlank(pluginName)) {
+            throw new JobDefineCheckException(
+                    String.format(
+                            "The '%s' option is not configured, please configure it.",
+                            PLUGIN_NAME.key()));
+        }
+        return pluginName;
     }
 
     public static String getFactoryId(Config config) {