Skip to content

Commit

Permalink
[DROOLS-91] fix property reactivity masks for inherited properties
Browse files Browse the repository at this point in the history
  • Loading branch information
mariofusco committed Mar 26, 2013
1 parent 69113ff commit 8f3c681
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1523,4 +1523,64 @@ public void testAvoidUnwantedSemicolonWhenDelimitingExpression() {

assertEquals("http://onefineday.123", l.get(0));
}

@Test
public void testScrambleProperties() {
// DROOLS-91
String str =
"package org.drools.test\n" +
" global java.util.List list" +
"\n" +
" declare Parent\n" +
" @propertyReactive\n" +
" a : int\n" +
" k : int\n" +
" z : int\n" +
" end\n" +
"\n" +
" declare Child extends Parent\n" +
" @propertyReactive\n" +
" p : int\n" +
" end\n" +
"\n" +
"\n" +
" rule Init\n" +
" when\n" +
" then\n" +
" insert( new Child( 1, 3, 5, 7 ) );\n" +
" end\n" +
"\n" +
" rule Mod\n" +
" when\n" +
" $p : Parent()\n" +
" then\n" +
" modify( $p ) { setZ( 99 ); }\n" +
" end\n" +
"\n" +
" rule React2\n" +
" when\n" +
" Child( p == 7 )\n" +
" then\n" +
" list.add( \"React2\" );\n" +
" end\n" +
"\n" +
" rule React\n" +
" when\n" +
" Child( z == 99 )\n" +
" then\n" +
" list.add( \"React\" );\n" +
" end";

KnowledgeBase kbase = loadKnowledgeBaseFromString(str);
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();

List<String> list = new ArrayList<String>();
ksession.setGlobal("list", list);

ksession.fireAllRules();

assertEquals(2, list.size());
assertTrue(list.contains("React"));
assertTrue(list.contains("React2"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ public void testFixThrows() {
String fixed = fixBlockDescr(context, analysis, context.getDeclarationResolver().getDeclarations( context.getRule() ) );

String expected =
" { $cheese.setPrice( 10 ); $cheese.setOldPrice( age ); drools.update( $cheese__Handle__, 12L ); }\r\n" +
" { $cheese.setPrice( 10 ); $cheese.setOldPrice( age ); drools.update( $cheese__Handle__, 6L ); }\r\n" +
" throw new java.lang.RuntimeException(\"xxx\");\r\n" +
" Cheese c1 = $cheese;\r\n" +
" { org.drools.compiler.Cheese __obj__ = ( c1 ); org.drools.core.FactHandle __obj____Handle2__ = drools.getFactHandle(__obj__);__obj__.setPrice( 10 ); __obj__.setOldPrice( age ); drools.update( __obj____Handle2__, 9223372036854775807L ); }\r\n" +
Expand Down Expand Up @@ -298,7 +298,7 @@ public void testFixModifyBlocks() throws Exception {
" Cheese c3 = $cheese;\r\n" +
" { org.drools.compiler.Cheese __obj__ = ( c3 ); org.drools.core.FactHandle __obj____Handle2__ = drools.getFactHandle(__obj__);__obj__.setPrice( 10 ); __obj__.setOldPrice( age ); drools.update( __obj____Handle2__, 9223372036854775807L ); }\r\n" +
" }\r\n" +
" { $cheese.setPrice( 10 ); $cheese.setOldPrice( age ); drools.update( $cheese__Handle__, 12L ); }\r\n" +
" { $cheese.setPrice( 10 ); $cheese.setOldPrice( age ); drools.update( $cheese__Handle__, 6L ); }\r\n" +
" System.out.println(\"we are done\");\r\n" +
" \r\n" +
"";
Expand Down
85 changes: 71 additions & 14 deletions drools-core/src/main/java/org/drools/core/util/ClassUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
Expand All @@ -48,6 +49,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.TreeSet;

public final class ClassUtils {
private static final ProtectionDomain PROTECTION_DOMAIN;
Expand All @@ -74,7 +76,7 @@ public static boolean areNullSafeEquals(Object obj1, Object obj2) {
* org/my/Class.xxx -> org.my.Class
*/
public static String convertResourceToClassName(final String pResourceName) {
return stripExtension(pResourceName).replace( '/', '.' );
return stripExtension(pResourceName).replace('/', '.');
}

/**
Expand All @@ -95,7 +97,7 @@ public static String convertClassToResourcePath(final String pName) {
* org/my/Class.xxx -> org/my/Class
*/
public static String stripExtension(final String pResourceName) {
final int i = pResourceName.lastIndexOf( '.' );
final int i = pResourceName.lastIndexOf('.');
return pResourceName.substring( 0, i );
}

Expand All @@ -111,7 +113,7 @@ public static String clazzName(final File base,
final String absFileName = file.getAbsolutePath();
final int p = absFileName.lastIndexOf( '.' );
final String relFileName = absFileName.substring( rootLength + 1, p );
return relFileName.replace( File.separatorChar, '.' );
return relFileName.replace(File.separatorChar, '.');
}

public static String relative(final File base,
Expand Down Expand Up @@ -339,32 +341,87 @@ public static Class<?> findClass(String className, ClassLoader cl) {
}

public static List<String> getSettableProperties(Class<?> clazz) {
Set<String> props = new HashSet<String>();
Set<SetterInClass> props = new TreeSet<SetterInClass>();
for (Method m : clazz.getMethods()) {
if (m.getParameterTypes().length == 1) {
String propName = setter2property(m.getName());
if (propName != null) {
props.add(propName);
props.add( new SetterInClass( propName, m.getDeclaringClass() ) );
}
}

Modifies modifies = m.getAnnotation( Modifies.class );
if (modifies != null) {
for (String prop : modifies.value()) {
props.add( prop.trim() );
}
}
processModifiesAnnotation(clazz, props, m);
}

for (Field f : clazz.getFields()) {
props.add(f.getName());
if ( !Modifier.isFinal(f.getModifiers()) && !Modifier.isStatic(f.getModifiers()) ) {
props.add( new SetterInClass( f.getName(), f.getDeclaringClass() ) );
}
}

List<String> settableProperties = new ArrayList<String>(props);
Collections.sort(settableProperties);
List<String> settableProperties = new ArrayList<String>();
for ( SetterInClass setter : props ) {
settableProperties.add(setter.setter);
}
return settableProperties;
}

private static void processModifiesAnnotation(Class<?> clazz, Set<SetterInClass> props, Method m) {
Modifies modifies = m.getAnnotation( Modifies.class );
if (modifies != null) {
for (String prop : modifies.value()) {
prop = prop.trim();
try {
Field field = clazz.getField(prop);
props.add( new SetterInClass( field.getName(), field.getDeclaringClass() ) );
} catch (NoSuchFieldException e) {
String getter = "get" + prop.substring(0, 1).toUpperCase() + prop.substring(1);
try {
Method method = clazz.getMethod(getter);
props.add( new SetterInClass( prop, method.getDeclaringClass() ) );
} catch (NoSuchMethodException e1) {
getter = "is" + prop.substring(0, 1).toUpperCase() + prop.substring(1);
try {
Method method = clazz.getMethod(getter);
props.add( new SetterInClass( prop, method.getDeclaringClass() ) );
} catch (NoSuchMethodException e2) {
throw new RuntimeException(e2);
}
}
}
}
}
}

private static class SetterInClass implements Comparable {
private final String setter;
private final Class<?> clazz;

private SetterInClass(String setter, Class<?> clazz) {
this.setter = setter;
this.clazz = clazz;
}

public int compareTo(Object o) {
SetterInClass other = (SetterInClass) o;
if (clazz == other.clazz) {
return setter.compareTo(other.setter);
}
return clazz.isAssignableFrom(other.clazz) ? -1 : 1;
}

@Override
public boolean equals(Object obj) {
SetterInClass other = (SetterInClass) obj;
return clazz == other.clazz && setter.equals(other.setter);
}

@Override
public int hashCode() {
return 29 * clazz.hashCode() + 31 * setter.hashCode();
}
}

public static String getter2property(String methodName) {
if (methodName.startsWith("get") && methodName.length() > 3) {
return Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
Expand Down

0 comments on commit 8f3c681

Please sign in to comment.