Index: drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java =================================================================== --- drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java (revision 15728) +++ drools-core/src/main/java/org/drools/reteoo/CompositeObjectSinkAdapter.java (revision 15731) @@ -67,7 +67,7 @@ final FieldIndex fieldIndex = registerFieldIndex( index, literalConstraint.getFieldExtractor() ); - if ( fieldIndex.getCount() >= this.alphaNodeHashingThreshold ) { + if ( fieldIndex.getCount() >= this.alphaNodeHashingThreshold && this.alphaNodeHashingThreshold != 0) { if ( !fieldIndex.isHashed() ) { hashSinks( fieldIndex ); } @@ -430,6 +430,8 @@ private long lvalue; private boolean bvalue; private double dvalue; + + private boolean isNull; private int hashCode; @@ -459,46 +461,84 @@ final Extractor extractor) { this.index = index; final ValueType vtype = extractor.getValueType(); + + isNull = extractor.isNullValue(null, value); + if ( vtype.isBoolean() ) { - this.bvalue = extractor.getBooleanValue( null, value ); this.type = BOOL; - this.setHashCode( this.bvalue ? 1231 : 1237 ); + if ( !isNull ) { + this.bvalue = extractor.getBooleanValue( null, value ); + this.setHashCode( this.bvalue ? 1231 : 1237 ); + } else { + this.setHashCode( 0 ); + } } else if ( vtype.isIntegerNumber() ) { - this.lvalue = extractor.getLongValue( null, value ); this.type = LONG; - this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) ); + if ( !isNull ) { + this.lvalue = extractor.getLongValue( null, value ); + this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) ); + } else { + this.setHashCode( 0 ); + } } else if ( vtype.isFloatNumber() ) { - this.dvalue = extractor.getDoubleValue( null, value ); this.type = DOUBLE; - final long temp = Double.doubleToLongBits( this.dvalue ); - this.setHashCode( (int) (temp ^ (temp >>> 32)) ); + if ( !isNull ) { + this.dvalue = extractor.getDoubleValue( null, value ); + final long temp = Double.doubleToLongBits( this.dvalue ); + this.setHashCode( (int) (temp ^ (temp >>> 32)) ); + } else { + this.setHashCode( 0 ); + } } else { - this.ovalue = extractor.getValue( null, value ); this.type = OBJECT; - this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 ); + if ( !isNull ) { + this.ovalue = extractor.getValue( null, value ); + this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 ); + } else { + this.setHashCode( 0 ); + } } } public void setValue(final int index, final FieldValue value) { this.index = index; + + this.isNull = value.isNull(); + if ( value.isBooleanField() ) { - this.bvalue = value.getBooleanValue(); this.type = BOOL; - this.setHashCode( this.bvalue ? 1231 : 1237 ); + if ( !isNull ) { + this.bvalue = value.getBooleanValue(); + this.setHashCode( this.bvalue ? 1231 : 1237 ); + } else { + this.setHashCode( 0 ); + } } else if ( value.isIntegerNumberField() ) { - this.lvalue = value.getLongValue(); this.type = LONG; - this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) ); + if ( !isNull ) { + this.lvalue = value.getLongValue(); + this.setHashCode( (int) (this.lvalue ^ (this.lvalue >>> 32)) ); + } else { + this.setHashCode( 0 ); + } } else if ( value.isFloatNumberField() ) { - this.dvalue = value.getDoubleValue(); this.type = DOUBLE; - final long temp = Double.doubleToLongBits( this.dvalue ); - this.setHashCode( (int) (temp ^ (temp >>> 32)) ); + if ( !isNull ) { + this.dvalue = value.getDoubleValue(); + final long temp = Double.doubleToLongBits( this.dvalue ); + this.setHashCode( (int) (temp ^ (temp >>> 32)) ); + } else { + this.setHashCode( 0 ); + } } else { - this.ovalue = value.getValue(); this.type = OBJECT; - this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 ); + if ( !isNull ) { + this.ovalue = value.getValue(); + this.setHashCode( this.ovalue != null ? this.ovalue.hashCode() : 0 ); + } else { + this.setHashCode( 0 ); + } } } @@ -598,6 +638,10 @@ public boolean equals(final Object object) { final HashKey other = (HashKey) object; + + if ( this.isNull ) { + return ( other.isNull ); + } switch ( this.type ) { case BOOL : Index: drools-compiler/src/test/java/org/drools/Attribute.java =================================================================== --- drools-compiler/src/test/java/org/drools/Attribute.java (revision 0) +++ drools-compiler/src/test/java/org/drools/Attribute.java (revision 15731) @@ -0,0 +1,14 @@ +/** + * + */ +package org.drools; + +public class Attribute +{ + + public Integer getValue() + { + return null; + } + +} \ No newline at end of file Index: drools-compiler/src/test/java/org/drools/Message.java =================================================================== --- drools-compiler/src/test/java/org/drools/Message.java (revision 15728) +++ drools-compiler/src/test/java/org/drools/Message.java (revision 15731) @@ -3,6 +3,10 @@ */ package org.drools; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + public class Message { private String message1 = "One"; @@ -17,6 +21,18 @@ private int status; + private List list = new ArrayList(); + private int number = 0; + private Date birthday = new Date(); + private boolean fired = false; + + public Message() { + } + + public Message(final String msg) { + this.message = msg; + } + public String getMessage() { return this.message; } @@ -64,4 +80,40 @@ public void setMessage4(final String message4) { this.message4 = message4; } + + public boolean isFired() { + return this.fired; + } + + public void setFired(final boolean fired) { + this.fired = fired; + } + + public Date getBirthday() { + return this.birthday; + } + + public void setBirthday(final Date birthday) { + this.birthday = birthday; + } + + public int getNumber() { + return this.number; + } + + public void setNumber(final int number) { + this.number = number; + } + + public List getList() { + return this.list; + } + + public void setList(final List list) { + this.list = list; + } + + public void addToList(final String s) { + this.list.add( s ); + } } \ No newline at end of file Index: drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java =================================================================== --- drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java (revision 15728) +++ drools-compiler/src/test/java/org/drools/integrationtests/MiscTest.java (revision 15731) @@ -39,6 +39,7 @@ import org.acme.insurance.Driver; import org.acme.insurance.Policy; import org.drools.Address; +import org.drools.Attribute; import org.drools.Cell; import org.drools.Cheese; import org.drools.Cheesery; @@ -96,7 +97,7 @@ import org.drools.event.WorkingMemoryEventListener; import org.drools.facttemplates.Fact; import org.drools.facttemplates.FactTemplate; -import org.drools.integrationtests.helloworld.Message; +import org.drools.Message; import org.drools.lang.DrlDumper; import org.drools.lang.descr.AttributeDescr; import org.drools.lang.descr.PackageDescr; @@ -110,6 +111,7 @@ import org.drools.spi.GlobalResolver; import org.drools.xml.XmlDumper; + /** Run all the tests with the ReteOO engine implementation */ public class MiscTest extends TestCase { @@ -397,7 +399,29 @@ list.size() ); } + + public void NullFieldOnCompositeSink() throws Exception { + final PackageBuilder builder = new PackageBuilder(); + builder.addPackageFromDrl( new InputStreamReader( getClass().getResourceAsStream( "test_NullFieldOnCompositeSink.drl" ) ) ); + final Package pkg = builder.getPackage(); + // add the package to a rulebase + final RuleBase ruleBase = getRuleBase(); + ruleBase.addPackage( pkg ); + + WorkingMemory workingMemory = ruleBase.newStatefulSession(); + List list = new ArrayList(); + workingMemory.setGlobal("list", list); + + workingMemory.insert(new Attribute()); + workingMemory.insert(new Message()); + workingMemory.fireAllRules(); + + assertEquals(1, list.size()); + assertEquals("X", list.get(0)); + + } + public void testEmptyPattern() throws Exception { // pre build the package final PackageBuilder builder = new PackageBuilder(); Index: drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java =================================================================== --- drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java (revision 15728) +++ drools-compiler/src/test/java/org/drools/integrationtests/ExecutionFlowControlTest.java (revision 15731) @@ -29,7 +29,7 @@ import org.drools.event.ActivationCreatedEvent; import org.drools.event.AgendaEventListener; import org.drools.event.DefaultAgendaEventListener; -import org.drools.integrationtests.helloworld.Message; +import org.drools.Message; import org.drools.lang.descr.PackageDescr; import org.drools.rule.Package; import org.drools.ruleflow.common.instance.ProcessInstance; Index: drools-compiler/src/test/resources/org/drools/integrationtests/test_NullFieldOnCompositeSink.drl =================================================================== --- drools-compiler/src/test/resources/org/drools/integrationtests/test_NullFieldOnCompositeSink.drl (revision 0) +++ drools-compiler/src/test/resources/org/drools/integrationtests/test_NullFieldOnCompositeSink.drl (revision 15731) @@ -0,0 +1,34 @@ +package org.drools + +import org.drools.Message; +import org.drools.Attribute; + +global java.util.List list; + +rule "rule_1" + +when + Message() + Attribute(value == 1) +then + System.err.println("case 1"); +end + +rule "rule_2" + +when + Message() + Attribute(value == 2) +then +System.err.println("case 2"); +end + + +rule "rule_3" + +when + Message() + $a:Attribute(value == null) +then + list.add( "X" ); +end \ No newline at end of file Index: drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl =================================================================== --- drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl (revision 15728) +++ drools-compiler/src/test/resources/org/drools/integrationtests/test_EffectiveDate.drl (revision 15731) @@ -9,7 +9,7 @@ date-effective "9-Jul-1974" date-expires "10-Jul-1974" when - $m : org.drools.integrationtests.helloworld.Message() + $m : org.drools.Message() then $m.setFired(true); end Index: drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl =================================================================== --- drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl (revision 15728) +++ drools-compiler/src/test/resources/org/drools/integrationtests/test_ExplicitAnd.drl (revision 15731) @@ -1,6 +1,6 @@ package HelloWorld -import org.drools.integrationtests.helloworld.Message +import org.drools.Message import org.drools.Cheese; global java.util.List list; Index: drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl =================================================================== --- drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl (revision 15728) +++ drools-compiler/src/test/resources/org/drools/integrationtests/HelloWorld.drl (revision 15731) @@ -7,7 +7,7 @@ rule "Hello World" when - $m : org.drools.integrationtests.helloworld.Message(list contains "hello", + $m : org.drools.Message(list contains "hello", text:message == "hola", number > 40, birthday > "10-Jul-1974",