Skip to content

Commit

Permalink
[DROOLS-7088] Property reactivity discrepancy between executable mode… (
Browse files Browse the repository at this point in the history
#4585) (#4800)

* [DROOLS-7088] Property reactivity discrepancy between executable model and non executable model with a capitalized property
- unit tests

* - fixed non-exec-model
- added more tests

- added import
  • Loading branch information
tkobayas authored Nov 9, 2022
1 parent 2ccfa5f commit d3702b8
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@
import org.drools.modelcompiler.domain.Person;
import org.drools.modelcompiler.domain.Pet;
import org.drools.modelcompiler.domain.Result;
import org.drools.modelcompiler.domain.VariousCasePropFact;
import org.junit.Test;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.Message.Level;
import org.kie.api.definition.type.Modifies;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.rule.FactHandle;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
Expand Down Expand Up @@ -1573,4 +1575,68 @@ public void testMvelModifyAfterSingleQuote() {
assertEquals(41, p.getAge());
assertEquals(1, ksession.getObjects((Object object) -> object.equals("ok")).size());
}

@Test
public void testOnlyFirstLetterIsUpperCaseProperty() {
// See JavaBeans 1.01 spec : 8.8 Capitalization of inferred names
// “FooBah” becomes “fooBah”
testVariousCasePropFact("modify($f) { MyTarget = \"123\" };", "R1", "R2"); // Actually, this modifies "myTarget" property (backed by private "MyTarget" field). This shouldn't react R1
}

@Test
public void testTwoFirstLettersAreUpperCaseProperty() {
// See JavaBeans 1.01 spec : 8.8 Capitalization of inferred names
// “URL” becomes “URL”
testVariousCasePropFact("modify($f) { URL = \"123\" };", "R1", "R2"); // This shouldn't react R1
}

@Test
public void testFirstLetterIsMultibyteProperty() {
// Multibyte is not mentioned in JavaBeans spec
testVariousCasePropFact("modify($f) { 名前 = \"123\" };", "R1", "R2"); // This shouldn't react R1
}

@Test
public void testOnlyFirstLetterIsUpperCaseAndMultibyteProperty() {
// Multibyte is not mentioned in JavaBeans spec
testVariousCasePropFact("modify($f) { My名前 = \"123\" };", "R1", "R2"); // Actually, this modifies "my名前" property (backed by private "My名前" field). This shouldn't react R1
}

@Test
public void testOnlyFirstLetterIsUpperCasePublicFieldProperty() {
testVariousCasePropFact("modify($f) { MyPublicTarget = \"123\" };", "R1", "R2"); // this modifies "MyPublicTarget" public field directly. This shouldn't react R1
}

private void testVariousCasePropFact(String modifyStatement, String... expectedResults) {
final String str =
"import " + VariousCasePropFact.class.getCanonicalName() + ";\n" +
"dialect \"mvel\"\n" +
"global java.util.List results;\n" +
"rule R1\n" +
"salience 100\n" +
"when\n" +
" $f : VariousCasePropFact( value == \"A\" )\n" +
"then\n" +
" results.add(\"R1\")\n" +
"end\n" +
"rule R2\n" +
"no-loop\n" +
"when\n" +
" $f : VariousCasePropFact( value == \"A\" )\n" +
"then\n" +
" results.add(\"R2\");\n" +
modifyStatement + "\n" +
"end\n";

KieSession ksession = getKieSession(str);
List<String> results = new ArrayList<>();
ksession.setGlobal("results", results);

VariousCasePropFact fact = new VariousCasePropFact();
fact.setValue("A");
ksession.insert(fact);
ksession.fireAllRules();

assertThat(results).containsExactly(expectedResults);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Copyright 2022 Red Hat, Inc. and/or its affiliates.
*
* 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 org.drools.modelcompiler.domain;

public class VariousCasePropFact {

private String value; // lower only
private String MyTarget; // upper + lower
private String URL; // upper + upper
private String 名前; // multibyte
private String My名前; // upper + lower + multibyte
public String MyPublicTarget; // public field : upper + lower

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

public String getMyTarget() {
return MyTarget;
}

public void setMyTarget(String myTarget) {
MyTarget = myTarget;
}

public String getURL() {
return URL;
}

public void setURL(String uRL) {
URL = uRL;
}

public String get名前() {
return 名前;
}

public void set名前(String 名前) {
this.名前 = 名前;
}

public String getMy名前() {
return My名前;
}

public void setMy名前(String my名前) {
My名前 = my名前;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

package org.drools.mvel.builder;

import java.beans.Introspector;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -269,6 +270,7 @@ public static String rewriteUpdates( Function<String, Class<?>> classResolver, F
continue;
}
BitMask modificationMask = getEmptyPropertyReactiveMask(settableProperties.size());
boolean directAccess = false;

for (String expr : splitStatements(text)) {
if (expr.startsWith( identifier + "." )) {
Expand All @@ -285,10 +287,12 @@ public static String rewriteUpdates( Function<String, Class<?>> classResolver, F
if (expr.length() > endMethodArgs+1 && expr.substring(endMethodArgs+1).trim().startsWith(".")) {
propertyName = Character.toLowerCase(propertyName.charAt(3)) + propertyName.substring(4);
}
} else {
directAccess = true;
}
}

int index = settableProperties.indexOf(propertyName);
int index = findPropertyIndex(settableProperties, propertyName, directAccess);
if (index >= 0) {
modificationMask = setPropertyOnMask(modificationMask, index);
} else {
Expand All @@ -307,6 +311,14 @@ public static String rewriteUpdates( Function<String, Class<?>> classResolver, F
return text;
}

private static int findPropertyIndex(List<String> settableProperties, String propertyName, boolean directAccess) {
int index = settableProperties.indexOf(propertyName);
if (index < 0 && directAccess) {
index = settableProperties.indexOf(Introspector.decapitalize(propertyName)); // e.g. "MyTarget" in mvel can be a property "myTarget"
}
return index;
}

public static String processMacros(String consequence) {
MacroProcessor macroProcessor = new MacroProcessor();
macroProcessor.setMacros( macros );
Expand Down

0 comments on commit d3702b8

Please sign in to comment.