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 4d8ac18a7e0 [incubator-kie-issues#6737] Allow declared enums to
reference other d… (#6738)
4d8ac18a7e0 is described below
commit 4d8ac18a7e0ed6d42687a1f51fe4f126d5cb435f
Author: Daniel Clark <[email protected]>
AuthorDate: Mon Jun 29 06:15:43 2026 +0200
[incubator-kie-issues#6737] Allow declared enums to reference other d…
(#6738)
* [incubator-kie-drools-6737] Allow declared enums to reference other
declared enums
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
* fast fail on non parseable enum declaration
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
---
.../generator/declaredtype/EnumGenerator.java | 21 ++-
.../model/codegen/execmodel/DeclaredTypesTest.java | 61 +++++++++
.../drools/mvel/asm/DefaultBeanClassBuilder.java | 47 ++++---
.../drools/mvel/asm/DefaultEnumClassBuilder.java | 12 +-
.../org/drools/mvel/asm/EnumLiteralEmitter.java | 146 +++++++++++++++++++++
.../org/drools/mvel/integrationtests/EnumTest.java | 32 +++++
.../drools/mvel/integrationtests/test_Enums.drl | 42 +++---
7 files changed, 321 insertions(+), 40 deletions(-)
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/declaredtype/EnumGenerator.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/declaredtype/EnumGenerator.java
index c5965e8d28e..0cf2404ca95 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/declaredtype/EnumGenerator.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/declaredtype/EnumGenerator.java
@@ -24,6 +24,8 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+import com.github.javaparser.ParseProblemException;
+import com.github.javaparser.StaticJavaParser;
import com.github.javaparser.ast.Modifier;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.EnumConstantDeclaration;
@@ -31,6 +33,7 @@ import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.FieldDeclaration;
import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.expr.Expression;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.stmt.BlockStmt;
import com.github.javaparser.ast.stmt.ReturnStmt;
@@ -104,8 +107,24 @@ public class EnumGenerator {
private void addEnumerationValue(EnumLiteralDescr enumLiteral) {
EnumConstantDeclaration element = new
EnumConstantDeclaration(enumLiteral.getName());
for (String constructorArgument : enumLiteral.getConstructorArgs()) {
- element.addArgument(new NameExpr(constructorArgument));
+ element.addArgument(parseConstructorArgument(enumLiteral,
constructorArgument));
}
enumDeclaration.addEntry(element);
}
+
+ /**
+ * Parses an enum-constant constructor argument as a Java expression.
+ */
+ private Expression parseConstructorArgument(EnumLiteralDescr enumLiteral,
+ String constructorArgument) {
+ try {
+ return StaticJavaParser.parseExpression(constructorArgument);
+ } catch (ParseProblemException e) {
+ throw new IllegalStateException(
+ "Failed to parse constructor argument '" + constructorArgument
+
+ "' for enum literal '" + enumLiteral.getName() +
+ "': " + e.getMessage(),
+ e);
+ }
+ }
}
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
index 3a1587b4a91..353caceb53f 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
@@ -515,6 +515,67 @@ public class DeclaredTypesTest extends BaseModelTest {
assertThat(p.getAge()).isEqualTo(11);
}
+ @ParameterizedTest
+ @MethodSource("parameters")
+ public void testEnumWithMisspelledConstantFailsAtCompileTime(RUN_TYPE
runType) {
+ // Diagnostic experience: a typo in a cross-enum reference must fail at
+ // compile time (with KieBuilder error messages), not at runtime via a
+ // mysterious ExceptionInInitializerError on first enum access.
+ String str =
+ "package org.example;\n" +
+ "declare enum Color\n" +
+ " RED, GREEN, BLUE;\n" +
+ "end\n" +
+ "declare enum Light\n" +
+ " STOP( Color.RED ),\n" +
+ " GO( Color.GRENE );\n" + // typo
+ " color: Color\n" +
+ "end\n";
+
+ Results results = createKieBuilder(runType, str).getResults();
+ List<Message> errors = results.getMessages(Message.Level.ERROR);
+ assertThat(errors).as("expected a compile error naming the bad
constant").isNotEmpty();
+ assertThat(errors.toString()).contains("GRENE");
+ }
+
+ @ParameterizedTest
+ @MethodSource("parameters")
+ public void testEnumWithDeclaredEnumField(RUN_TYPE runType) {
+ String str =
+ "package org.example;\n" +
+ "import " + Result.class.getCanonicalName() + ";\n" +
+ "\n" +
+ "declare enum Category\n" +
+ " TARGET(\"target\"),\n" +
+ " NON_TARGET(\"non-target\"),\n" +
+ " NEW_LESION(\"new\");\n" +
+ "\n" +
+ " code: String\n" +
+ "end\n" +
+ "\n" +
+ "declare enum LesionState\n" +
+ " TARGET_PRESENT( org.example.Category.TARGET,
\"present\" ),\n" + // fully-qualified
+ " NON_TARGET_ABSENT( Category.NON_TARGET,
\"absent\" ),\n" + // simple (same package)
+ " NEW_PRESENT( Category.NEW_LESION,
\"present\" );\n" + // simple (same package)
+ "\n" +
+ " category: org.example.Category\n" +
+ " nominal: String\n" +
+ "end\n" +
+ "\n" +
+ "rule \"emit\"\n" +
+ " when\n" +
+ " then\n" +
+ " insert(new
Result(LesionState.TARGET_PRESENT.getCategory().getCode()));\n" +
+ " insert(new
Result(LesionState.NON_TARGET_ABSENT.getCategory() == Category.NON_TARGET));\n"
+
+ "end\n";
+
+ KieSession ksession = getKieSession(runType, str);
+ ksession.fireAllRules();
+
+ Collection<Result> results = getObjectsIntoList(ksession,
Result.class);
+ assertThat(results).extracting(Result::getValue).contains("target",
true);
+ }
+
@ParameterizedTest
@MethodSource("parameters")
public void testDeclaredSlidingWindowOnEventInTypeDeclaration(RUN_TYPE
runType) throws Exception {
diff --git
a/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultBeanClassBuilder.java
b/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultBeanClassBuilder.java
index e7cda9ce63e..998dd75ac2a 100755
--- a/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultBeanClassBuilder.java
+++ b/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultBeanClassBuilder.java
@@ -110,7 +110,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
buildFieldTMS( cw, classDef );
}
- buildConstructors( cw, classDef );
+ buildConstructors( cw, classDef, classLoader );
buildGettersAndSetters( cw, classDef );
buildEqualityMethods( cw, classDef );
buildToString( cw, classDef );
@@ -453,11 +453,12 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
}
- protected void buildConstructors(ClassWriter cw, ClassDefinition classDef)
{
+ protected void buildConstructors(ClassWriter cw, ClassDefinition classDef,
ClassLoader classLoader) {
// Building default constructor
try {
this.buildDefaultConstructor( cw,
- classDef );
+ classDef,
+ classLoader );
} catch (Exception e) {
LOG.error("Exception", e);
}
@@ -466,7 +467,8 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
if (classDef.getFieldsDefinitions().size() > 0 &&
classDef.getFieldsDefinitions().size() < 120) {
this.buildConstructorWithFields( cw,
classDef,
- classDef.getFieldsDefinitions() );
+ classDef.getFieldsDefinitions(),
+ classLoader );
}
// Building constructor with key fields only
@@ -479,7 +481,8 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
if ( !keys.isEmpty() && keys.size() !=
classDef.getFieldsDefinitions().size() ) {
this.buildConstructorWithFields( cw,
classDef,
- keys );
+ keys,
+ classLoader );
}
}
@@ -925,7 +928,8 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
* @param cw
*/
protected void buildDefaultConstructor(ClassVisitor cw,
- ClassDefinition classDef) {
+ ClassDefinition classDef,
+ ClassLoader classLoader) {
MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
@@ -942,7 +946,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
mv.visitLabel( l0 );
}
- boolean hasObjects = defaultConstructorStart( mv, classDef );
+ boolean hasObjects = defaultConstructorStart( mv, classDef,
classLoader );
mv.visitInsn(Opcodes.RETURN);
Label l1;
@@ -962,7 +966,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
}
- protected boolean defaultConstructorStart( MethodVisitor mv,
ClassDefinition classDef ) {
+ protected boolean defaultConstructorStart( MethodVisitor mv,
ClassDefinition classDef, ClassLoader classLoader ) {
// Building default constructor
mv.visitVarInsn( Opcodes.ALOAD,
@@ -983,7 +987,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
boolean hasObjects = false;
for (FieldDefinition field : classDef.getFieldsDefinitions()) {
- hasObjects = hasObjects || initFieldWithDefaultValue( mv,
classDef, field );
+ hasObjects = hasObjects || initFieldWithDefaultValue( mv,
classDef, field, classLoader );
}
@@ -995,7 +999,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
}
- protected boolean initFieldWithDefaultValue( MethodVisitor mv,
ClassDefinition classDef, FieldDefinition field ) {
+ protected boolean initFieldWithDefaultValue( MethodVisitor mv,
ClassDefinition classDef, FieldDefinition field, ClassLoader classLoader ) {
if ( field.getInitExpr() == null && field.isInherited() ) {
return false;
}
@@ -1030,12 +1034,14 @@ public class DefaultBeanClassBuilder implements
Opcodes, BeanClassBuilder, Seria
// there's a complex init expression
if ( field.getInitExpr() != null ) {
mv.visitVarInsn( ALOAD, 0 );
- mv.visitLdcInsn( field.getInitExpr() );
- mv.visitMethodInsn( INVOKESTATIC,
- "org/mvel2/MVEL",
- "eval",
- "(Ljava/lang/String;)Ljava/lang/Object;");
- mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType(
field.getTypeName() ) );
+ if ( !EnumLiteralEmitter.tryEmit( mv, field.getInitExpr(),
field.getTypeName(), classLoader ) ) {
+ mv.visitLdcInsn( field.getInitExpr() );
+ mv.visitMethodInsn( INVOKESTATIC,
+ "org/mvel2/MVEL",
+ "eval",
+
"(Ljava/lang/String;)Ljava/lang/Object;");
+ mv.visitTypeInsn( CHECKCAST, BuildUtils.getInternalType(
field.getTypeName() ) );
+ }
val = field.getInitExpr();
}
}
@@ -1120,7 +1126,8 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
*/
protected void buildConstructorWithFields(ClassVisitor cw,
ClassDefinition classDef,
- Collection<FieldDefinition>
fieldDefs) {
+ Collection<FieldDefinition>
fieldDefs,
+ ClassLoader classLoader) {
Type[] params = new Type[fieldDefs.size()];
@@ -1142,7 +1149,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
mv.visitLabel( l0 );
}
- fieldConstructorStart( mv, classDef, fieldDefs );
+ fieldConstructorStart( mv, classDef, fieldDefs, classLoader );
mv.visitInsn( Opcodes.RETURN );
Label l1;
@@ -1172,7 +1179,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
}
- protected void fieldConstructorStart(MethodVisitor mv, ClassDefinition
classDef, Collection<FieldDefinition> fieldDefs) {
+ protected void fieldConstructorStart(MethodVisitor mv, ClassDefinition
classDef, Collection<FieldDefinition> fieldDefs, ClassLoader classLoader) {
mv.visitVarInsn( Opcodes.ALOAD,
0 );
@@ -1224,7 +1231,7 @@ public class DefaultBeanClassBuilder implements Opcodes,
BeanClassBuilder, Seria
for ( FieldDefinition field : classDef.getFieldsDefinitions() ) {
if ( ! fieldDefs.contains( field ) && field.getInitExpr() != null
&& ! "".equals( field.getInitExpr().trim() ) ) {
- initFieldWithDefaultValue( mv, classDef, field );
+ initFieldWithDefaultValue( mv, classDef, field, classLoader );
}
}
diff --git
a/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultEnumClassBuilder.java
b/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultEnumClassBuilder.java
index 3695be04d05..57cca3aa86d 100755
--- a/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultEnumClassBuilder.java
+++ b/drools-mvel/src/main/java/org/drools/mvel/asm/DefaultEnumClassBuilder.java
@@ -75,7 +75,8 @@ public class DefaultEnumClassBuilder implements Opcodes,
EnumClassBuilder, Seria
this.buildConstructors( cw,
- edef );
+ edef,
+ classLoader );
this.buildGettersAndSetters( cw,
edef );
@@ -140,7 +141,7 @@ public class DefaultEnumClassBuilder implements Opcodes,
EnumClassBuilder, Seria
}
- protected void buildConstructors(ClassWriter cw, EnumClassDefinition
classDef) {
+ protected void buildConstructors(ClassWriter cw, EnumClassDefinition
classDef, ClassLoader classLoader) {
MethodVisitor mv;
final StringBuilder argTypesBuilder = new StringBuilder();
int size = 0;
@@ -205,8 +206,13 @@ public class DefaultEnumClassBuilder implements Opcodes,
EnumClassBuilder, Seria
List<String> args = lit.getConstructorArgs();
for ( int k = 0; k < args.size(); k++ ) {
String argType = classDef.getField( k ).getTypeName();
+ String argValue = args.get( k );
- mv.visitLdcInsn( args.get( k ) );
+ if ( EnumLiteralEmitter.tryEmit( mv, argValue, argType,
classLoader ) ) {
+ continue;
+ }
+
+ mv.visitLdcInsn( argValue );
mv.visitMethodInsn( INVOKESTATIC,
"org/mvel2/MVEL",
"eval",
diff --git
a/drools-mvel/src/main/java/org/drools/mvel/asm/EnumLiteralEmitter.java
b/drools-mvel/src/main/java/org/drools/mvel/asm/EnumLiteralEmitter.java
new file mode 100644
index 00000000000..5d2a318c9bc
--- /dev/null
+++ b/drools-mvel/src/main/java/org/drools/mvel/asm/EnumLiteralEmitter.java
@@ -0,0 +1,146 @@
+/*
+ * 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.mvel.asm;
+
+import java.lang.reflect.Field;
+
+import org.drools.compiler.builder.impl.classbuilder.BuildUtils;
+import org.mvel2.asm.MethodVisitor;
+import org.mvel2.asm.Opcodes;
+
+/**
+ * Compile-time detection and ASM emission of fully-qualified enum-constant
+ * references in declared-type field initializers and declared-enum constructor
+ * arguments.
+ */
+final class EnumLiteralEmitter {
+
+ private EnumLiteralEmitter() { }
+
+ /**
+ * If {@code expression} is a reference to an enum constant whose declaring
+ * class equals {@code expectedTypeName}, emit a direct {@code GETSTATIC}
+ * on {@code mv} and return {@code true}. Both fully-qualified
+ * ({@code "com.example.Category.TARGET"}) and simple
+ * ({@code "Category.TARGET"}) forms are accepted; the simple form is
+ * unambiguous because {@code expectedTypeName} has already been resolved
+ * by the type resolver against the DRL's imports and same-package types.
+ * Returns {@code false} for primitive targets, references that don't
+ * match the expected type's name, or anything that doesn't resolve to an
+ * enum constant via {@code classLoader}.
+ */
+ static boolean tryEmit(MethodVisitor mv,
+ String expression,
+ String expectedTypeName,
+ ClassLoader classLoader) {
+ if (expression == null || expectedTypeName == null) {
+ return false;
+ }
+ if (BuildUtils.isPrimitive(expectedTypeName) ||
expectedTypeName.indexOf('.') < 0) {
+ return false;
+ }
+ String trimmed = expression.trim();
+ String constantName = stripExpectedTypePrefix(trimmed,
expectedTypeName);
+ if (constantName == null || constantName.isEmpty() ||
!isJavaIdentifier(constantName)) {
+ return false;
+ }
+ Class<?> argClass;
+ try {
+ argClass = Class.forName(expectedTypeName, false, classLoader);
+ } catch (ClassNotFoundException | LinkageError e) {
+ return false;
+ }
+ if (!argClass.isEnum()) {
+ return false;
+ }
+ // From this point on, the user has clearly written the argument as an
+ // enum-constant reference of the expected enum type. Any failure is a
+ // user-facing error: surface it at compile time instead of letting
+ // MVEL.eval fail mysteriously at class load.
+ Field field;
+ try {
+ field = argClass.getField(constantName);
+ } catch (NoSuchFieldException e) {
+ throw new IllegalStateException(
+ "Enum constant '" + constantName + "' does not exist on '" +
expectedTypeName
+ + "'. Available constants: " +
listEnumConstantNames(argClass));
+ }
+ if (!field.isEnumConstant()) {
+ throw new IllegalStateException(
+ "Field '" + constantName + "' on '" + expectedTypeName
+ + "' is not an enum constant.");
+ }
+ mv.visitFieldInsn(Opcodes.GETSTATIC,
+ BuildUtils.getInternalType(expectedTypeName),
+ constantName,
+ BuildUtils.getTypeDescriptor(expectedTypeName));
+ return true;
+ }
+
+ private static String listEnumConstantNames(Class<?> enumClass) {
+ Object[] constants = enumClass.getEnumConstants();
+ if (constants == null) {
+ return "[]";
+ }
+ StringBuilder sb = new StringBuilder("[");
+ for (int i = 0; i < constants.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(((Enum<?>) constants[i]).name());
+ }
+ return sb.append("]").toString();
+ }
+
+ /**
+ * Returns the constant name suffix if {@code expression} starts with
either
+ * the FQN of {@code expectedTypeName} followed by a dot, or with the
+ * expected type's simple name followed by a dot. Returns {@code null}
+ * otherwise. The FQN form is tried first so a fully-qualified reference
+ * always wins when the simple name happens to be a prefix of something
+ * else.
+ */
+ private static String stripExpectedTypePrefix(String expression, String
expectedTypeName) {
+ String fqnPrefix = expectedTypeName + ".";
+ if (expression.startsWith(fqnPrefix)) {
+ return expression.substring(fqnPrefix.length());
+ }
+ int lastDot = expectedTypeName.lastIndexOf('.');
+ if (lastDot < 0) {
+ return null;
+ }
+ String simplePrefix = expectedTypeName.substring(lastDot + 1) + ".";
+ if (expression.startsWith(simplePrefix)) {
+ return expression.substring(simplePrefix.length());
+ }
+ return null;
+ }
+
+ private static boolean isJavaIdentifier(String s) {
+ if (s.isEmpty() || !Character.isJavaIdentifierStart(s.charAt(0))) {
+ return false;
+ }
+ for (int i = 1; i < s.length(); i++) {
+ if (!Character.isJavaIdentifierPart(s.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/EnumTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/EnumTest.java
index 9d0e288c512..959cc00b58e 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/EnumTest.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/integrationtests/EnumTest.java
@@ -60,10 +60,42 @@ public class EnumTest {
assertThat(list.contains(4)).isTrue();
assertThat(list.contains(5.976e+24)).isTrue();
assertThat(list.contains("Mercury")).isTrue();
+ assertThat(list.contains("TUESDAY")).isTrue();
+ assertThat(list.contains(true)).isTrue();
+ assertThat(list.contains("MONDAY")).isTrue();
ksession.dispose();
}
+ @ParameterizedTest(name = "KieBase type={0}")
+ @MethodSource("parameters")
+ public void
testCrossEnumReferenceWithMisspelledConstant(KieBaseTestConfiguration
kieBaseTestConfiguration) {
+ // Regression test for the diagnostic experience around the
+ // declared-enum cross-reference feature: a misspelled constant name
+ // must fail at compile time with a message that names the bad
+ // constant, not at runtime via a buried ExceptionInInitializerError
+ // on first enum access. The legacy ASM path additionally enriches the
+ // message with the list of available constants; the executable-model
+ // path relies on the underlying Java compiler (ECJ), whose default
+ // "X cannot be resolved or is not a field" wording satisfies the
+ // shared contract.
+ final String drl =
+ "package org.test;\n" +
+ "declare enum Color\n" +
+ " RED, GREEN, BLUE;\n" +
+ "end\n" +
+ "declare enum Light\n" +
+ " STOP( Color.RED ),\n" +
+ " GO( Color.GRENE );\n" + // typo: GRENE → GREEN
+ " color: Color\n" +
+ "end\n";
+
+ KieBuilder kieBuilder =
KieUtil.getKieBuilderFromDrls(kieBaseTestConfiguration, false, drl);
+ List<Message> errors =
kieBuilder.getResults().getMessages(Message.Level.ERROR);
+ assertThat(errors).as("expected a compile error naming the bad
constant").isNotEmpty();
+ assertThat(errors.toString()).contains("GRENE");
+ }
+
@ParameterizedTest(name = "KieBase type={0}")
@MethodSource("parameters")
public void testEnumsWithCompositeBuildingProcess(KieBaseTestConfiguration
kieBaseTestConfiguration) throws Exception {
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/resources/org/drools/mvel/integrationtests/test_Enums.drl
b/drools-test-coverage/test-compiler-integration/src/test/resources/org/drools/mvel/integrationtests/test_Enums.drl
index 8ccacfc764e..29c082956ff 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/resources/org/drools/mvel/integrationtests/test_Enums.drl
+++
b/drools-test-coverage/test-compiler-integration/src/test/resources/org/drools/mvel/integrationtests/test_Enums.drl
@@ -26,14 +26,14 @@ declare enum DaysOfWeek
end
declare enum Planets
- MERCURY ( 3.303e+23, 2.4397e6, new String("Mer") + new
String("cury").substring(0) ),
- VENUS ( 4.869e+24, 6.0518e6, "Venus" ),
+ MERCURY ( 3.303e+23, 2.4397e6, new String("Mer") + new
String("cury").substring(0) ),
+ VENUS ( 4.869e+24, 6.0518e6, "Venus" ),
EARTH ( 5.976e+24, 6.37814e6, "Earth" ),
- MARS ( 6.421e+23, 3.3972e6, "Mars" ),
- JUPITER ( 1.9e+27, 7.1492e7, "Jupiter" ),
- SATURN ( 5.688e+26, 6.0268e7, "Saturn" ),
- URANUS ( 8.686e+25, 2.5559e7, "Uranus" ),
- NEPTUNE ( 1.024e+26, 2.4746e7, "Neptune" );
+ MARS ( 6.421e+23, 3.3972e6, "Mars" ),
+ JUPITER ( 1.9e+27, 7.1492e7, "Jupiter" ),
+ SATURN ( 5.688e+26, 6.0268e7, "Saturn" ),
+ URANUS ( 8.686e+25, 2.5559e7, "Uranus" ),
+ NEPTUNE ( 1.024e+26, 2.4746e7, "Neptune" );
mass : double
radius : double
@@ -43,15 +43,11 @@ end
declare enum WorkLoad
-// LIGHT( x.DaysOfWeek.TUESDAY, 4 ),
-// MEDIUM( x.DaysOfWeek.MONDAY, 8 ),
-// HEAVY( x.DaysOfWeek.SUNDAY, 12 );
+ LIGHT( x.DaysOfWeek.TUESDAY, 4 ), // fully-qualified
+ MEDIUM( DaysOfWeek.MONDAY, 8 ), // simple name (in scope: same
package)
+ HEAVY( DaysOfWeek.SUNDAY, 12 ); // simple name
- LIGHT( 4 ),
- MEDIUM( 8 ),
- HEAVY( 12 );
-
-// day : DaysOfWeek
+ day : DaysOfWeek
hours : int
end
@@ -64,7 +60,7 @@ end
declare Test
load : WorkLoad
planet : Planets
- day : DaysOfWeek //= DaysOfWeek.MONDAY
+ day : DaysOfWeek = x.DaysOfWeek.MONDAY
num : int = 111
pers : Person //= new Person("xyz",18)
end
@@ -90,4 +86,18 @@ when
Test( WorkLoad.LIGHT, Planets.MARS, DaysOfWeek.MONDAY ; $h : load.hours )
then
list.add( $h );
+end
+
+rule "Test4_CrossEnumField"
+when
+then
+ list.add( WorkLoad.LIGHT.getDay().name() );
+ list.add( WorkLoad.HEAVY.getDay() == DaysOfWeek.SUNDAY );
+end
+
+rule "Test5_DeclaredTypeEnumDefault"
+when
+then
+ Test t = new Test();
+ list.add( t.getDay().name() );
end
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]