This is an automated email from the ASF dual-hosted git repository.

tkobayas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-drools.git


The following commit(s) were added to refs/heads/main by this push:
     new fe01cf8434 [incubator-kie-drools-6561] Update supported java versions 
> 19 for DRL compilation (#6569)
fe01cf8434 is described below

commit fe01cf8434d59c8feb3b2404f1a8b0eb0b595ef8
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Fri Jan 30 18:31:10 2026 +0900

    [incubator-kie-drools-6561] Update supported java versions > 19 for DRL 
compilation (#6569)
    
    * [incubator-kie-drools-6561] Update supported java versions > 19
    - Add java versions for DRL java compilation
    - Upgrade eclipse-ecj from 3.33.0 to 3.44.0
    - Java 21 syntax test
    - Not support dialect "mvel" yet
      - drools-mvel is deprecated
      - drools-model/mvel.jj is based on Java 16 now. Enhancement would be a 
separate issue/PR
    - WIP
    
    * add native compile test and ecj compile test
    
    * refactor to remove duplicate java version definitions
    
    * Remove java version 1.7 check because eclipse-ecj 3.44.0 supports 1.8 and 
higher
    
    * add kie-maven-plugin kjar test
    
    * Apply copilot suggestion. Remove unnecessary test for java 1.6
    
    * default is 17
    
    * further refactoring to reduce duplication
    
    * ensure language level normalization
---
 build-parent/pom.xml                               |  2 +-
 .../java/org/drools/ecj/EclipseJavaCompiler.java   | 12 ++++
 .../drools/ecj/EclipseJavaCompilerSettings.java    | 63 ++---------------
 .../java/org/drools/ecj/JavaCompilerI18NTest.java  |  4 +-
 .../test/java/org/drools/ecj/Jdk21SyntaxTest.java  | 81 ++++++++++++++++++++++
 .../codegen/execmodel/generator/DrlxParseUtil.java |  6 +-
 .../codegen/execmodel/jdk/Jdk21SyntaxTest.java     | 68 ++++++++++++++++++
 .../compilers/NativeJavaCompilerSettingsTest.java  |  8 +--
 .../integrationtests/SwitchOverStringTest.java     | 19 +----
 .../invoker.properties                             | 29 ++++++++
 .../kie-maven-plugin-test-kjar-16-java21/pom.xml   | 71 +++++++++++++++++++
 .../src/main/resources/META-INF/kmodule.xml        | 27 ++++++++
 .../src/main/resources/org/java21test/rules.drl    | 34 +++++++++
 .../maven/plugin/ittests/Java21SyntaxTestIT.java   | 73 +++++++++++++++++++
 .../kie/memorycompiler/JavaCompilerFactory.java    |  5 +-
 .../kie/memorycompiler/JavaCompilerSettings.java   |  6 ++
 .../org/kie/memorycompiler/JavaConfiguration.java  | 48 ++++++-------
 .../kie/memorycompiler/KieMemoryCompilerTest.java  | 32 +++++++++
 18 files changed, 477 insertions(+), 111 deletions(-)

diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index f6a6f8406e..a0262d7fe5 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -94,7 +94,7 @@
     <version.org.apache.poi>5.4.1</version.org.apache.poi>
     
<version.org.apache.tomcat.tomcat-dbcp>10.1.48</version.org.apache.tomcat.tomcat-dbcp>
     <version.org.assertj>3.27.3</version.org.assertj>
-    <version.org.eclipse.jdt>3.33.0</version.org.eclipse.jdt>
+    <version.org.eclipse.jdt>3.44.0</version.org.eclipse.jdt>
     <version.org.freemarker>2.3.32</version.org.freemarker>
     <version.org.glassfish.jaxb>4.0.6</version.org.glassfish.jaxb>
     <!--This needs to be in sync with JUnit-->
diff --git a/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompiler.java 
b/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompiler.java
index 8cc9cd652f..5fc08c86a5 100644
--- a/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompiler.java
+++ b/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompiler.java
@@ -45,6 +45,8 @@ import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
 import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
 import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
+import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment;
+import org.eclipse.jdt.internal.compiler.lookup.ModuleBinding;
 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
 import org.kie.memorycompiler.AbstractJavaCompiler;
 import org.kie.memorycompiler.CompilationProblem;
@@ -156,6 +158,16 @@ public final class EclipseJavaCompiler extends 
AbstractJavaCompiler {
         public boolean ignoreOptionalProblems() {
             return true;
         }
+
+        @Override
+        public char[] getModuleName() {
+            return ModuleBinding.UNNAMED;
+        }
+
+        @Override
+        public ModuleBinding module(LookupEnvironment environment) {
+            return environment.getModule(ModuleBinding.UNNAMED);
+        }
     }
 
 
diff --git 
a/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompilerSettings.java 
b/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompilerSettings.java
index d56c6b2b25..28b25b096c 100644
--- a/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompilerSettings.java
+++ b/drools-ecj/src/main/java/org/drools/ecj/EclipseJavaCompilerSettings.java
@@ -24,30 +24,12 @@ import java.util.Map;
 import org.kie.memorycompiler.JavaCompilerSettings;
 
 /**
- * Native Eclipse compiler settings
+ * Native Eclipse compiler settings.
+ *
+ * Supported Java version strings are defined in {@link 
org.kie.memorycompiler.JavaConfiguration#LANGUAGE_LEVELS}.
+ * Version strings are passed through to the Eclipse compiler as-is.
  */
 public final class EclipseJavaCompilerSettings extends JavaCompilerSettings {
-    
-  //copied from org.eclipse.jdt.internal.compiler.impl.CompilerOptions as we 
can't access it
-    public static final String CompilerOptions_VERSION_1_1 = "1.1"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_2 = "1.2"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_3 = "1.3"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_4 = "1.4"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_JSR14 = "jsr14"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_CLDC1_1 = "cldc1.1"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_5 = "1.5"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_6 = "1.6"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_7 = "1.7"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_1_8 = "1.8"; 
//$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_9 = "9"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_10 = "10"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_11 = "11"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_12 = "12"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_15 = "15"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_16 = "16"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_17 = "17"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_18 = "18"; //$NON-NLS-1$
-    public static final String CompilerOptions_VERSION_19 = "19"; //$NON-NLS-1$
 
     public static final String CompilerOptions_GENERATE = 
"generate";//$NON-NLS-1$
     public static final String CompilerOptions_DO_NOT_GENERATE = "do not 
generate"; //$NON-NLS-1$
@@ -90,46 +72,15 @@ public final class EclipseJavaCompilerSettings extends 
JavaCompilerSettings {
         defaultEclipseSettings.putAll(pMap);
     }
 
-    private static Map nativeVersions = new HashMap() {
-        private static final long serialVersionUID = 510l;
-    {
-        put("1.1", CompilerOptions_VERSION_1_1);
-        put("1.2", CompilerOptions_VERSION_1_2);
-        put("1.3", CompilerOptions_VERSION_1_3);
-        put("1.4", CompilerOptions_VERSION_1_4);
-        put("1.5", CompilerOptions_VERSION_1_5);
-        put("1.6", CompilerOptions_VERSION_1_6);
-        put("1.7", CompilerOptions_VERSION_1_7);
-        put("1.8", CompilerOptions_VERSION_1_8);
-        put("9", CompilerOptions_VERSION_9);
-        put("10", CompilerOptions_VERSION_10);
-        put("11", CompilerOptions_VERSION_11);
-        put("12", CompilerOptions_VERSION_12);
-        put("15", CompilerOptions_VERSION_15);
-        put("16", CompilerOptions_VERSION_16);
-        put("17", CompilerOptions_VERSION_17);
-        put("18", CompilerOptions_VERSION_18);
-        put("19", CompilerOptions_VERSION_19);
-    }};
-    
-    private String toNativeVersion( final String pVersion ) {
-        final String nativeVersion = (String) nativeVersions.get(pVersion);
-
-        if (nativeVersion == null) {
-            throw new RuntimeException("unknown version " + pVersion);
-        }
-
-        return nativeVersion;
-    }
     
     Map toNativeSettings() {
         final Map map = new HashMap(defaultEclipseSettings);
 
         map.put(CompilerOptions_OPTION_SuppressWarnings, 
isWarnings()?CompilerOptions_GENERATE:CompilerOptions_DO_NOT_GENERATE);
         map.put(CompilerOptions_OPTION_ReportDeprecation, 
isDeprecations()?CompilerOptions_GENERATE:CompilerOptions_DO_NOT_GENERATE);
-        map.put(CompilerOptions_OPTION_TargetPlatform, 
toNativeVersion(getTargetVersion()));
-        map.put(CompilerOptions_OPTION_Source, 
toNativeVersion(getSourceVersion()));
-        map.put(CompilerOptions_OPTION_Compliance, 
toNativeVersion(getSourceVersion()));
+        map.put(CompilerOptions_OPTION_TargetPlatform, getTargetVersion());
+        map.put(CompilerOptions_OPTION_Source, getSourceVersion());
+        map.put(CompilerOptions_OPTION_Compliance, getSourceVersion());
         map.put(CompilerOptions_OPTION_Encoding, getSourceEncoding());
 
         return map;
diff --git a/drools-ecj/src/test/java/org/drools/ecj/JavaCompilerI18NTest.java 
b/drools-ecj/src/test/java/org/drools/ecj/JavaCompilerI18NTest.java
index ab364f90ff..2262ffc681 100644
--- a/drools-ecj/src/test/java/org/drools/ecj/JavaCompilerI18NTest.java
+++ b/drools-ecj/src/test/java/org/drools/ecj/JavaCompilerI18NTest.java
@@ -43,8 +43,8 @@ public class JavaCompilerI18NTest {
         reader.add(fileStr, fileContents.getBytes());
 
         EclipseJavaCompilerSettings settings = new 
EclipseJavaCompilerSettings();
-        settings.setSourceVersion( "1.5" );
-        settings.setTargetVersion( "1.5" );
+        settings.setSourceVersion( "17" );
+        settings.setTargetVersion( "17" );
         EclipseJavaCompiler compiler = new EclipseJavaCompiler( settings, "" );
         CompilationResult res = compiler.compile( classes.toArray( new 
String[classes.size()] ), reader, store );
         assertThat(0).isEqualTo(res.getErrors().length);
diff --git a/drools-ecj/src/test/java/org/drools/ecj/Jdk21SyntaxTest.java 
b/drools-ecj/src/test/java/org/drools/ecj/Jdk21SyntaxTest.java
new file mode 100644
index 0000000000..510c446199
--- /dev/null
+++ b/drools-ecj/src/test/java/org/drools/ecj/Jdk21SyntaxTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.drools.ecj;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
+import org.kie.memorycompiler.CompilationResult;
+import org.kie.memorycompiler.KieMemoryCompiler;
+import org.kie.memorycompiler.resources.MemoryResourceReader;
+import org.kie.memorycompiler.resources.MemoryResourceStore;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@EnabledForJreRange(min = JRE.JAVA_21)
+class Jdk21SyntaxTest {
+
+    private static final String JDK21_TYPE_SWITCH_CLASS = """
+            package org.kie.memorycompiler;
+            
+            public class ExampleClass {
+            
+                public String typeSwitch(Object obj) {
+                    return switch (obj) {
+                      case Integer i -> "int: " + i;
+                      case String s  -> "string: " + s;
+                      default        -> "other";
+                    };
+                }
+            }
+            """;
+
+    @Test
+    void jdk21typeSwitch() throws Exception {
+        String fileStr = "org/kie/memorycompiler/ExampleClass.java";
+        List<String> classes = new ArrayList<>();
+        classes.add(fileStr);
+
+        MemoryResourceReader reader = new MemoryResourceReader();
+        MemoryResourceStore store = new MemoryResourceStore();
+
+        reader.add(fileStr, JDK21_TYPE_SWITCH_CLASS.getBytes());
+
+        EclipseJavaCompilerSettings settings = new 
EclipseJavaCompilerSettings();
+        settings.setSourceVersion("21");
+        settings.setTargetVersion("21");
+        EclipseJavaCompiler compiler = new EclipseJavaCompiler(settings, "");
+        CompilationResult res = compiler.compile(classes.toArray(new 
String[classes.size()]), reader, store);
+        assertThat(res.getErrors()).isEmpty();
+
+        byte[] byteCode = store.getResources().values().iterator().next();
+        KieMemoryCompiler.MemoryCompilerClassLoader 
kieMemoryCompilerClassLoader = new 
KieMemoryCompiler.MemoryCompilerClassLoader(this.getClass().getClassLoader());
+        String className = "org.kie.memorycompiler.ExampleClass";
+        kieMemoryCompilerClassLoader.addCode(className, byteCode);
+        Class<?> exampleClazz = 
kieMemoryCompilerClassLoader.loadClass(className);
+        Object instance = 
exampleClazz.getDeclaredConstructors()[0].newInstance();
+        Method typeSwitchMethod = exampleClazz.getMethod("typeSwitch", 
Object.class);
+        Object result = typeSwitchMethod.invoke(instance, 51);
+        assertThat(result).isEqualTo("int: 51");
+    }
+}
diff --git 
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
 
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
index d06c9aa663..d29fe8f592 100644
--- 
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
+++ 
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/DrlxParseUtil.java
@@ -124,6 +124,10 @@ import static org.drools.util.MethodUtils.findMethod;
 
 public class DrlxParseUtil {
 
+    // Regardless of the configured language level, always parse with the 
highest level at this point,
+    // so compiler will report any incompatible syntax at the compilation 
phase.
+    public static final ParserConfiguration.LanguageLevel 
PARSABLE_LANGUAGE_LEVEL = ParserConfiguration.LanguageLevel.JAVA_21;
+
     public static final String THIS_PLACEHOLDER = "_this";
 
     private static final ConcurrentMap<String, Method> ACCESSOR_CACHE = new 
ConcurrentHashMap<>();
@@ -497,7 +501,7 @@ public class DrlxParseUtil {
 
     public static BlockStmt parseBlock(String ruleConsequenceAsBlock) {
         ParserConfiguration parserConfiguration = new ParserConfiguration();
-        
parserConfiguration.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_15);
+        parserConfiguration.setLanguageLevel(PARSABLE_LANGUAGE_LEVEL);
         com.github.javaparser.JavaParser javaParser = new 
com.github.javaparser.JavaParser(parserConfiguration);
 
         ParseResult<BlockStmt> blockStmtParseResult = 
javaParser.parseBlock(String.format("{%n%s%n}", ruleConsequenceAsBlock));
diff --git 
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/jdk/Jdk21SyntaxTest.java
 
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/jdk/Jdk21SyntaxTest.java
new file mode 100644
index 0000000000..fff0594986
--- /dev/null
+++ 
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/jdk/Jdk21SyntaxTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.drools.model.codegen.execmodel.jdk;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.drools.model.codegen.execmodel.BaseModelTest;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.kie.api.runtime.KieSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test class to verify syntax features introduced in JDK 21
+ * Note: at the moment, this class tests only dialect "java" (default),
+ * because drools-mvel (non-exec-model) is deprecated,
+ * and drools-model/mvel.jj (exec-model) enhancement would be a separate task.
+ */
+@EnabledForJreRange(min = JRE.JAVA_21)
+class Jdk21SyntaxTest extends BaseModelTest {
+
+    @ParameterizedTest
+    @MethodSource("parameters")
+    void testTypeSwitch(RUN_TYPE runType) {
+        String str = """
+                global java.util.List results;
+                
+                rule R1
+                  when
+                    $obj : Object()
+                  then
+                    String message = switch ($obj) {
+                      case Integer i -> "int: " + i;
+                      case String s  -> "string: " + s;
+                      default        -> "other";
+                    };
+                    results.add(message);
+                end
+                """;
+
+        KieSession ksession = getKieSession(runType, str);
+        List<String> results = new ArrayList<>();
+        ksession.setGlobal("results", results);
+        ksession.insert(51);
+        ksession.fireAllRules();
+        assertThat(results).containsExactly("int: 51");
+    }
+}
diff --git 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/commons/jci/compilers/NativeJavaCompilerSettingsTest.java
 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/commons/jci/compilers/NativeJavaCompilerSettingsTest.java
index 6f65e7ec29..c0f3ce19ba 100644
--- 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/commons/jci/compilers/NativeJavaCompilerSettingsTest.java
+++ 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/commons/jci/compilers/NativeJavaCompilerSettingsTest.java
@@ -47,8 +47,8 @@ public class NativeJavaCompilerSettingsTest {
         settings.setWarnings(true);
         settings.setDeprecations(true);
         settings.setSourceEncoding("My-Custom-Encoding");
-        settings.setSourceVersion("1.9");
-        settings.setTargetVersion("1.9");
+        settings.setSourceVersion("9");
+        settings.setTargetVersion("9");
         List<String> options = settings.toOptionsList();
 
         assertThat(options).hasSize(9);
@@ -56,8 +56,8 @@ public class NativeJavaCompilerSettingsTest {
         assertThat(options).contains("-Xlint:all");
         assertThat(options).contains("-deprecation");
         // check the order is correct, value of the option needs to be right 
after the option name
-        assertThat(options).contains("1.9", 
Index.atIndex(options.indexOf("-source") + 1));
-        assertThat(options).contains("1.9", 
Index.atIndex(options.indexOf("-target") + 1));
+        assertThat(options).contains("9", 
Index.atIndex(options.indexOf("-source") + 1));
+        assertThat(options).contains("9", 
Index.atIndex(options.indexOf("-target") + 1));
         assertThat(options).contains("My-Custom-Encoding", 
Index.atIndex(options.indexOf("-encoding") + 1));
     }
 
diff --git 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/SwitchOverStringTest.java
 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/SwitchOverStringTest.java
index f362d2716d..fac3c2079b 100644
--- 
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/SwitchOverStringTest.java
+++ 
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/SwitchOverStringTest.java
@@ -59,9 +59,8 @@ public class SwitchOverStringTest {
     @ParameterizedTest(name = "KieBase type={0}")
     @MethodSource("parameters")
     public void 
testCompileSwitchOverStringWithLngLevel17(KieBaseTestConfiguration 
kieBaseTestConfiguration) {
-        double javaVersion = 
Double.valueOf(System.getProperty("java.specification.version"));
-        Assumptions.assumeTrue(javaVersion >= 1.7, "Test only makes sense on 
Java 7+.");
-        System.setProperty("drools.dialect.java.compiler.lnglevel", "1.7");
+        // Switch Over String is supported since Java 7. Set 17 here, because 
17 is the minimum level supported in Drools 10
+        System.setProperty("drools.dialect.java.compiler.lnglevel", "17");
         try {
             KieBuilder kieBuilder = 
KieUtil.getKieBuilderFromDrls(kieBaseTestConfiguration, false, 
FUNCTION_WITH_SWITCH_OVER_STRING);
             List<Message> errors = 
kieBuilder.getResults().getMessages(Message.Level.ERROR);
@@ -70,18 +69,4 @@ public class SwitchOverStringTest {
             System.clearProperty("drools.dialect.java.compiler.lnglevel");
         }
     }
-
-    @ParameterizedTest(name = "KieBase type={0}")
-    @MethodSource("parameters")
-    public void 
testShouldFailToCompileSwitchOverStringWithLngLevel16(KieBaseTestConfiguration 
kieBaseTestConfiguration) {
-        System.setProperty("drools.dialect.java.compiler.lnglevel", "1.6");
-        try {
-            KieBuilder kieBuilder = 
KieUtil.getKieBuilderFromDrls(kieBaseTestConfiguration, false, 
FUNCTION_WITH_SWITCH_OVER_STRING);
-            List<Message> errors = 
kieBuilder.getResults().getMessages(Message.Level.ERROR);
-            assertThat(errors.isEmpty()).as("Should have an error").isFalse();
-            
-        } finally {
-            System.clearProperty("drools.dialect.java.compiler.lnglevel");
-        }
-    }
 }
diff --git 
a/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/invoker.properties
 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/invoker.properties
new file mode 100644
index 0000000000..32f00a5bc0
--- /dev/null
+++ 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/invoker.properties
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+# A comma or space separated list of goals/phases to execute, may
+# specify an empty list to execute the default goal of the IT project.
+# Environment variables used by maven plugins can be added here
+invoker.goals = clean install
+
+# Require Java 21 for type switch syntax
+invoker.java.version = 21+
+
+# Uncomment the following to debug invoker. Do note that you have to connect 
the remote debugger after "maven-invoker-plugin:3.2.0:run" has been print on 
console
+#invoker.mavenOpts=-Xdebug -Xnoagent 
-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
diff --git 
a/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/pom.xml 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/pom.xml
new file mode 100644
index 0000000000..2ccf87a143
--- /dev/null
+++ b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xmlns="http://maven.apache.org/POM/4.0.0";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.kie</groupId>
+    <artifactId>kie-maven-plugin-test-kjar-parent</artifactId>
+    <version>@org.kie.version@</version>
+    
<relativePath>../kie-maven-plugin-test-kjar-setup/kie-maven-plugin-test-kjar-parent/pom.xml</relativePath>
+  </parent>
+
+  <artifactId>kie-maven-plugin-test-kjar-16-java21</artifactId>
+
+  <packaging>kjar</packaging>
+
+  <properties>
+    <!-- Override parent's Java 11 to require Java 21 for type switch syntax 
-->
+    <maven.compiler.release>21</maven.compiler.release>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.kie</groupId>
+      <artifactId>kie-api</artifactId>
+      <version>${org.kie.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-core</artifactId>
+      <version>${org.kie.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-compiler</artifactId>
+      <version>${org.kie.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.drools</groupId>
+      <artifactId>drools-mvel</artifactId>
+      <version>${org.kie.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.kie</groupId>
+      <artifactId>kie-maven-plugin-test-kjar-common</artifactId>
+      <version>@org.kie.version@</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git 
a/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/META-INF/kmodule.xml
 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/META-INF/kmodule.xml
new file mode 100644
index 0000000000..c30e4f6d5a
--- /dev/null
+++ 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/META-INF/kmodule.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+
+<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule";>
+  <kbase name="Java21KBase" packages="org.java21test">
+    <ksession name="Java21KBase.session" type="stateful"/>
+  </kbase>
+</kmodule>
diff --git 
a/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/org/java21test/rules.drl
 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/org/java21test/rules.drl
new file mode 100644
index 0000000000..2e40b69baf
--- /dev/null
+++ 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/main/resources/org/java21test/rules.drl
@@ -0,0 +1,34 @@
+/**
+ * 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.java21test
+
+global java.util.List results;
+
+rule "TypeSwitchRule"
+  when
+    $obj : Object()
+  then
+    String message = switch ($obj) {
+      case Integer i -> "int: " + i;
+      case String s  -> "string: " + s;
+      default        -> "other";
+    };
+    results.add(message);
+end
diff --git 
a/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/test/java-filtered/org/kie/maven/plugin/ittests/Java21SyntaxTestIT.java
 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/test/java-filtered/org/kie/maven/plugin/ittests/Java21SyntaxTestIT.java
new file mode 100644
index 0000000000..2aab43f332
--- /dev/null
+++ 
b/kie-maven-plugin/src/it/kie-maven-plugin-test-kjar-16-java21/src/test/java-filtered/org/kie/maven/plugin/ittests/Java21SyntaxTestIT.java
@@ -0,0 +1,73 @@
+/*
+ * 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.kie.maven.plugin.ittests;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
+import org.kie.api.runtime.KieSession;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test to verify Java 21 type switch syntax works in DRL rules
+ * when built with kie-maven-plugin.
+ */
+@EnabledForJreRange(min = JRE.JAVA_21)
+public class Java21SyntaxTestIT {
+
+    private static final String GAV_ARTIFACT_ID = 
"kie-maven-plugin-test-kjar-16-java21";
+    private static final String GAV_VERSION = "${org.kie.version}";
+    private static final String KBASE_NAME = "Java21KBase";
+
+    @Test
+    public void testTypeSwitch() throws Exception {
+        final URL targetLocation = 
Java21SyntaxTestIT.class.getProtectionDomain().getCodeSource().getLocation();
+        KieSession kSession = ITTestsUtils.getKieSession(targetLocation, 
GAV_ARTIFACT_ID, GAV_VERSION, KBASE_NAME);
+
+        try {
+            List<String> results = new ArrayList<>();
+            kSession.setGlobal("results", results);
+
+            // Test with Integer - should match "case Integer i"
+            kSession.insert(51);
+            kSession.fireAllRules();
+            assertThat(results).containsExactly("int: 51");
+
+            // Test with String - should match "case String s"
+            results.clear();
+            kSession.insert("hello");
+            kSession.fireAllRules();
+            assertThat(results).contains("string: hello");
+
+            // Test with Double - should match "default"
+            results.clear();
+            kSession.insert(3.14);
+            kSession.fireAllRules();
+            assertThat(results).contains("other");
+
+        } finally {
+            kSession.dispose();
+        }
+    }
+}
diff --git 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerFactory.java
 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerFactory.java
index 3c08626577..e653feef98 100644
--- 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerFactory.java
+++ 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerFactory.java
@@ -41,9 +41,10 @@ public class JavaCompilerFactory {
     }
 
     private static JavaCompilerSettings createSettings( JavaCompiler compiler, 
String lngLevel ) {
+        String normalizedLevel = JavaConfiguration.findJavaVersion( lngLevel );
         JavaCompilerSettings settings = compiler.createDefaultSettings();
-        settings.setTargetVersion( lngLevel );
-        settings.setSourceVersion( lngLevel );
+        settings.setTargetVersion( normalizedLevel );
+        settings.setSourceVersion( normalizedLevel );
         return settings;
     }
 
diff --git 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerSettings.java
 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerSettings.java
index 2660aaa915..03dcf900e3 100644
--- 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerSettings.java
+++ 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaCompilerSettings.java
@@ -60,6 +60,9 @@ public class JavaCompilerSettings {
     }
     
     public void setTargetVersion( final String pTargetVersion ) {
+        if (!JavaConfiguration.isValidLanguageLevel(pTargetVersion)) {
+            throw new RuntimeException("value '" + pTargetVersion + "' is not 
a valid language level");
+        }
         targetVersion = pTargetVersion;
     }
 
@@ -69,6 +72,9 @@ public class JavaCompilerSettings {
 
 
     public void setSourceVersion( final String pSourceVersion ) {
+        if (!JavaConfiguration.isValidLanguageLevel(pSourceVersion)) {
+            throw new RuntimeException("value '" + pSourceVersion + "' is not 
a valid language level");
+        }
         sourceVersion = pSourceVersion;
     }
 
diff --git 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaConfiguration.java
 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaConfiguration.java
index d497e3eaeb..835bea0e4c 100644
--- 
a/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaConfiguration.java
+++ 
b/kie-memory-compiler/src/main/java/org/kie/memorycompiler/JavaConfiguration.java
@@ -31,16 +31,16 @@ import org.kie.memorycompiler.jdknative.NativeJavaCompiler;
  * The valid values are "ECLIPSE" and "NATIVE" only.
  * 
  * drools.dialect.java.compiler = <ECLIPSE|NATIVE>
- * drools.dialect.java.compiler.lnglevel = <1.5|1.6>
+ * drools.dialect.java.compiler.lnglevel = <1.5|...|21>
  * 
- * The default compiler is Eclipse and the default lngLevel is 1.5.
+ * The default compiler is Eclipse and the default lngLevel is 17.
  * The lngLevel will attempt to autodiscover your system using the 
  * system property "java.version"
  */
 public class JavaConfiguration {
 
     // This should be in alphabetic order to search with BinarySearch
-    protected static final String[]  LANGUAGE_LEVELS = new String[]{"1.5", 
"1.6", "1.7", "1.8", "10", "11", "12", "13", "14", "15", "16", "17", "18", 
"19", "9"};
+    protected static final String[]  LANGUAGE_LEVELS = new String[]{"1.5", 
"1.6", "1.7", "1.8", "10", "11", "12", "13", "14", "15", "16", "17", "18", 
"19", "20", "21", "9"};
 
     public static final String JAVA_COMPILER_PROPERTY = 
"drools.dialect.java.compiler";
     public static final String JAVA_LANG_LEVEL_PROPERTY = 
"drools.dialect.java.compiler.lnglevel";
@@ -85,32 +85,24 @@ public class JavaConfiguration {
         return findJavaVersion( System.getProperty( JAVA_LANG_LEVEL_PROPERTY, 
System.getProperty("java.version") ) );
     }
 
+    public static boolean isValidLanguageLevel(String level) {
+        return Arrays.binarySearch(LANGUAGE_LEVELS, level) >= 0;
+    }
+
     public static String findJavaVersion(String level) {
-        if (level.startsWith("1.5")) {
-            return "1.5";
-        } else if (level.startsWith("1.6")) {
-            return "1.6";
-        } else if (level.startsWith("1.7")) {
-            return "1.7";
-        } else if (level.startsWith("1.8")) {
-            return "1.8";
-        } else if (level.startsWith("9")) {
-            return "9";
-        } else if (level.startsWith("10")) {
-            return "10";
-        } else if (level.startsWith("15")) {
-            return "15";
-        } else if (level.startsWith("16")) {
-            return "16";
-        } else if (level.startsWith("17")) {
-            return "17";
-        } else if (level.startsWith("18")) {
-            return "18";
-        } else if (level.startsWith("19")) {
-            return "19";
+        String normalized = normalizeVersion(level);
+        if (isValidLanguageLevel(normalized)) {
+            return normalized;
         }
+        return "17"; // default
+    }
 
-        return "11";
+    private static String normalizeVersion(String version) {
+        String[] parts = version.split("\\.");
+        if ("1".equals(parts[0]) && parts.length > 1) {
+            return "1." + parts[1]; // Legacy format: 1.8.0_292 -> 1.8
+        }
+        return parts[0]; // Modern format: 21.0.2 -> 21
     }
 
     public String getJavaLanguageLevel() {
@@ -118,11 +110,11 @@ public class JavaConfiguration {
     }
 
     /**
-     * You cannot set language level below 1.5, as we need static imports, 1.5 
is now the default.
+     * You cannot set language level below 1.5, as we need static imports. 17 
is now the default.
      * @param languageLevel
      */
     public void setJavaLanguageLevel(final String languageLevel) {
-        if ( Arrays.binarySearch( LANGUAGE_LEVELS, languageLevel ) < 0 ) {
+        if (!isValidLanguageLevel(languageLevel)) {
             throw new RuntimeException( "value '" + languageLevel + "' is not 
a valid language level" );
         }
         this.languageLevel = languageLevel;
diff --git 
a/kie-memory-compiler/src/test/java/org/kie/memorycompiler/KieMemoryCompilerTest.java
 
b/kie-memory-compiler/src/test/java/org/kie/memorycompiler/KieMemoryCompilerTest.java
index ec9dca17c3..017b5691f8 100644
--- 
a/kie-memory-compiler/src/test/java/org/kie/memorycompiler/KieMemoryCompilerTest.java
+++ 
b/kie-memory-compiler/src/test/java/org/kie/memorycompiler/KieMemoryCompilerTest.java
@@ -22,6 +22,8 @@ import java.lang.reflect.Method;
 import java.util.Map;
 
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledForJreRange;
+import org.junit.jupiter.api.condition.JRE;
 
 import static java.util.Collections.singletonMap;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -115,4 +117,34 @@ public class KieMemoryCompilerTest {
         
assertThat(compiled.get("org.kie.memorycompiler.ExampleClass")).isNotNull();
         
assertThat(compiled.get("org.kie.memorycompiler.ExampleClass$InnerClass")).isNotNull();
     }
+
+    private static final String JDK21_TYPE_SWITCH_CLASS = """
+            package org.kie.memorycompiler;
+            
+            public class ExampleClass {
+            
+                public String typeSwitch(Object obj) {
+                    return switch (obj) {
+                      case Integer i -> "int: " + i;
+                      case String s  -> "string: " + s;
+                      default        -> "other";
+                    };
+                }
+            }
+            """;
+
+    @EnabledForJreRange(min = JRE.JAVA_21)
+    @Test
+    void jdk21typeSwitch() throws Exception {
+        Map<String, String> source = 
singletonMap("org.kie.memorycompiler.ExampleClass", JDK21_TYPE_SWITCH_CLASS);
+        Map<String, Class<?>> compiled = KieMemoryCompiler.compile(source, 
this.getClass().getClassLoader());
+
+        Class<?> exampleClazz = 
compiled.get("org.kie.memorycompiler.ExampleClass");
+        assertThat(exampleClazz).isNotNull();
+
+        Object instance = 
exampleClazz.getDeclaredConstructors()[0].newInstance();
+        Method typeSwitchMethod = exampleClazz.getMethod("typeSwitch", 
Object.class);
+        Object result = typeSwitchMethod.invoke(instance, 51);
+        assertThat(result).isEqualTo("int: 51");
+    }
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to