You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2015/05/23 12:48:32 UTC

cayenne git commit: unit test reorg by expression type , some cleanup and fixing warnings

Repository: cayenne
Updated Branches:
  refs/heads/master 069b8fbb2 -> 5faca1c3a


unit test reorg by expression type , some cleanup and fixing warnings


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/5faca1c3
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/5faca1c3
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/5faca1c3

Branch: refs/heads/master
Commit: 5faca1c3a48e291022c6f7516b6d6afdf0d543db
Parents: 069b8fb
Author: aadamchik <aa...@apache.org>
Authored: Sat May 23 13:18:10 2015 +0300
Committer: aadamchik <aa...@apache.org>
Committed: Sat May 23 13:48:24 2015 +0300

----------------------------------------------------------------------
 .../apache/cayenne/exp/parser/ASTDivide.java    |   4 +-
 .../org/apache/cayenne/exp/parser/ASTEqual.java | 252 ++++++++++---------
 .../org/apache/cayenne/exp/parser/ASTFalse.java |  84 ++++---
 .../apache/cayenne/exp/parser/ASTGreater.java   |  84 ++++---
 .../cayenne/exp/parser/ASTGreaterOrEqual.java   |  86 +++----
 .../org/apache/cayenne/exp/parser/ASTIn.java    | 191 +++++++-------
 .../org/apache/cayenne/exp/parser/ASTLess.java  |  85 ++++---
 .../cayenne/exp/parser/ASTLessOrEqual.java      |  84 ++++---
 .../apache/cayenne/exp/parser/ASTInTest.java    |  73 ++++++
 .../parser/ExpressionEvaluateInMemoryTest.java  |  43 +---
 10 files changed, 517 insertions(+), 469 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java
index 66b92a8..7e48b8c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTDivide.java
@@ -53,10 +53,10 @@ public class ASTDivide extends SimpleNode {
 		connectChildren();
 	}
 
-	public ASTDivide(Collection nodes) {
+	public ASTDivide(Collection<?> nodes) {
 		super(ExpressionParserTreeConstants.JJTDIVIDE);
 		int len = nodes.size();
-		Iterator it = nodes.iterator();
+		Iterator<?> it = nodes.iterator();
 		for (int i = 0; i < len; i++) {
 			jjtAddChild(wrapChild(it.next()), i);
 		}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEqual.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEqual.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEqual.java
index c6b6806..579545d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEqual.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTEqual.java
@@ -32,129 +32,131 @@ import org.apache.commons.logging.LogFactory;
  * @since 1.1
  */
 public class ASTEqual extends ConditionNode implements ValueInjector {
-    
-    private static final Log logObj = LogFactory.getLog(ASTEqual.class);
-
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTEqual(int id) {
-        super(id);
-    }
-
-    public ASTEqual() {
-        super(ExpressionParserTreeConstants.JJTEQUAL);
-    }
-
-    /**
-     * Creates "Equal To" expression.
-     */
-    public ASTEqual(ASTPath path, Object value) {
-        super(ExpressionParserTreeConstants.JJTEQUAL);
-        jjtAddChild(path, 0);
-        jjtAddChild(new ASTScalar(value), 1);
-        connectChildren();
-    }
-
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
-
-        Object o1 = evaluateChild(0, o);
-        Object o2 = evaluateChild(1, o);
-
-        return evaluateImpl(o1, o2);
-    }
-
-    /**
-     * Compares two objects, if one of them is array, 'in' operation is
-     * performed
-     */
-    static boolean evaluateImpl(Object o1, Object o2) {
-        // TODO: maybe we need a comparison "strategy" here, instead of
-        // a switch of all possible cases? ... there were other requests for
-        // more relaxed type-unsafe comparison (e.g. numbers to strings)
-
-        if (o1 == null && o2 == null) {
-            return true;
-        } else if (o1 != null) {
-
-            // Per CAY-419 we perform 'in' comparison if one object is a list,
-            // and other is not
-
-            if (o1 instanceof List && !(o2 instanceof List)) {
-                for (Object element : ((List<?>) o1)) {
-                    if (element != null && Evaluator.evaluator(element).eq(element, o2)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-            if (o2 instanceof List && !(o1 instanceof List)) {
-                for (Object element : ((List<?>) o2)) {
-                    if (element != null && Evaluator.evaluator(element).eq(element, o1)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            return Evaluator.evaluator(o1).eq(o1, o2);
-        }
-        return false;
-    }
-
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTEqual(id);
-    }
-
-    @Override
-    protected String getExpressionOperator(int index) {
-        return "=";
-    }
-
-    @Override
-    protected String getEJBQLExpressionOperator(int index) {
-        if (jjtGetChild(1) instanceof ASTScalar && ((ASTScalar) jjtGetChild(1)).getValue() == null) {
-            // for ejbql, we need "is null" instead of "= null"
-            return "is";
-        }
-        return getExpressionOperator(index);
-    }
-
-    @Override
-    public int getType() {
-        return Expression.EQUAL_TO;
-    }
-
-    public void injectValue(Object o) {
-        // try to inject value, if one of the operands is scalar, and other is a
-        // path
-
-        Node[] args = new Node[] { jjtGetChild(0), jjtGetChild(1) };
-
-        int scalarIndex = -1;
-        if (args[0] instanceof ASTScalar) {
-            scalarIndex = 0;
-        } else if (args[1] instanceof ASTScalar) {
-            scalarIndex = 1;
-        }
-
-        if (scalarIndex != -1 && args[1 - scalarIndex] instanceof ASTObjPath) {
-            // inject
-            ASTObjPath path = (ASTObjPath) args[1 - scalarIndex];
-            try {
-                path.injectValue(o, evaluateChild(scalarIndex, o));
-            } catch (Exception ex) {
-                logObj.warn("Failed to inject value " + " on path " + path.getPath() + " to " + o, ex);
-            }
-        }
-    }
+
+	private static final long serialVersionUID = 1211234198602067833L;
+	
+	private static final Log LOGGER = LogFactory.getLog(ASTEqual.class);
+
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTEqual(int id) {
+		super(id);
+	}
+
+	public ASTEqual() {
+		super(ExpressionParserTreeConstants.JJTEQUAL);
+	}
+
+	/**
+	 * Creates "Equal To" expression.
+	 */
+	public ASTEqual(ASTPath path, Object value) {
+		super(ExpressionParserTreeConstants.JJTEQUAL);
+		jjtAddChild(path, 0);
+		jjtAddChild(new ASTScalar(value), 1);
+		connectChildren();
+	}
+
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
+
+		Object o1 = evaluateChild(0, o);
+		Object o2 = evaluateChild(1, o);
+
+		return evaluateImpl(o1, o2);
+	}
+
+	/**
+	 * Compares two objects, if one of them is array, 'in' operation is
+	 * performed
+	 */
+	static boolean evaluateImpl(Object o1, Object o2) {
+		// TODO: maybe we need a comparison "strategy" here, instead of
+		// a switch of all possible cases? ... there were other requests for
+		// more relaxed type-unsafe comparison (e.g. numbers to strings)
+
+		if (o1 == null && o2 == null) {
+			return true;
+		} else if (o1 != null) {
+
+			// Per CAY-419 we perform 'in' comparison if one object is a list,
+			// and other is not
+
+			if (o1 instanceof List && !(o2 instanceof List)) {
+				for (Object element : ((List<?>) o1)) {
+					if (element != null && Evaluator.evaluator(element).eq(element, o2)) {
+						return true;
+					}
+				}
+				return false;
+			}
+			if (o2 instanceof List && !(o1 instanceof List)) {
+				for (Object element : ((List<?>) o2)) {
+					if (element != null && Evaluator.evaluator(element).eq(element, o1)) {
+						return true;
+					}
+				}
+				return false;
+			}
+
+			return Evaluator.evaluator(o1).eq(o1, o2);
+		}
+		return false;
+	}
+
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTEqual(id);
+	}
+
+	@Override
+	protected String getExpressionOperator(int index) {
+		return "=";
+	}
+
+	@Override
+	protected String getEJBQLExpressionOperator(int index) {
+		if (jjtGetChild(1) instanceof ASTScalar && ((ASTScalar) jjtGetChild(1)).getValue() == null) {
+			// for ejbql, we need "is null" instead of "= null"
+			return "is";
+		}
+		return getExpressionOperator(index);
+	}
+
+	@Override
+	public int getType() {
+		return Expression.EQUAL_TO;
+	}
+
+	public void injectValue(Object o) {
+		// try to inject value, if one of the operands is scalar, and other is a
+		// path
+
+		Node[] args = new Node[] { jjtGetChild(0), jjtGetChild(1) };
+
+		int scalarIndex = -1;
+		if (args[0] instanceof ASTScalar) {
+			scalarIndex = 0;
+		} else if (args[1] instanceof ASTScalar) {
+			scalarIndex = 1;
+		}
+
+		if (scalarIndex != -1 && args[1 - scalarIndex] instanceof ASTObjPath) {
+			// inject
+			ASTObjPath path = (ASTObjPath) args[1 - scalarIndex];
+			try {
+				path.injectValue(o, evaluateChild(scalarIndex, o));
+			} catch (Exception ex) {
+				LOGGER.warn("Failed to inject value " + " on path " + path.getPath() + " to " + o, ex);
+			}
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFalse.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFalse.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFalse.java
index e59f9f9..a117cba 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFalse.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFalse.java
@@ -29,7 +29,7 @@ import org.apache.cayenne.exp.Expression;
  * Notice that there is one ASTTrue and one ASTFalse instead of a ASTBoolean
  * with a Boolean value. The main reason for doing this is that a common
  * ASTBoolean will have operand count of 1 and that will default to a prepared
- * statmenet like " where ? and (...)", but we only need " where true and
+ * statement like " where ? and (...)", but we only need " where true and
  * (...)".
  * 
  * @see ASTTrue
@@ -37,51 +37,53 @@ import org.apache.cayenne.exp.Expression;
  */
 public class ASTFalse extends ConditionNode {
 
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTFalse(int id) {
-        super(id);
-    }
+	private static final long serialVersionUID = -8441997825701749863L;
 
-    public ASTFalse() {
-        super(ExpressionParserTreeConstants.JJTFALSE);
-    }
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTFalse(int id) {
+		super(id);
+	}
 
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        return Boolean.FALSE;
-    }
+	public ASTFalse() {
+		super(ExpressionParserTreeConstants.JJTFALSE);
+	}
 
-    @Override
-    protected String getExpressionOperator(int index) {
-        throw new UnsupportedOperationException("No operator for '" + ExpressionParserTreeConstants.jjtNodeName[id]
-                + "'");
-    }
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		return Boolean.FALSE;
+	}
 
-    @Override
-    public Expression shallowCopy() {
-        return new ASTFalse(id);
-    }
+	@Override
+	protected String getExpressionOperator(int index) {
+		throw new UnsupportedOperationException("No operator for '" + ExpressionParserTreeConstants.jjtNodeName[id]
+				+ "'");
+	}
 
-    @Override
-    public int getType() {
-        return Expression.FALSE;
-    }
+	@Override
+	public Expression shallowCopy() {
+		return new ASTFalse(id);
+	}
 
-    /**
-     * @since 4.0
-     */
-    @Override
-    public void appendAsString(Appendable out) throws IOException {
-        out.append("false");
-    }
+	@Override
+	public int getType() {
+		return Expression.FALSE;
+	}
 
-    /**
-     * @since 4.0
-     */
-    @Override
-    public void appendAsEJBQL(List<Object> parameterAccumulator, Appendable out, String rootId) throws IOException {
-        out.append("false");
-    }
+	/**
+	 * @since 4.0
+	 */
+	@Override
+	public void appendAsString(Appendable out) throws IOException {
+		out.append("false");
+	}
+
+	/**
+	 * @since 4.0
+	 */
+	@Override
+	public void appendAsEJBQL(List<Object> parameterAccumulator, Appendable out, String rootId) throws IOException {
+		out.append("false");
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
index 575eb2b..f990e24 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreater.java
@@ -26,53 +26,55 @@ import org.apache.cayenne.exp.Expression;
  */
 public class ASTGreater extends ConditionNode {
 
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTGreater(int id) {
-        super(id);
-    }
+	private static final long serialVersionUID = 2796092142001150018L;
 
-    public ASTGreater() {
-        super(ExpressionParserTreeConstants.JJTGREATER);
-    }
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTGreater(int id) {
+		super(id);
+	}
 
-    public ASTGreater(ASTPath path, Object value) {
-        super(ExpressionParserTreeConstants.JJTGREATER);
-        jjtAddChild(path, 0);
-        jjtAddChild(new ASTScalar(value), 1);
-        connectChildren();
-    }
+	public ASTGreater() {
+		super(ExpressionParserTreeConstants.JJTGREATER);
+	}
 
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
+	public ASTGreater(ASTPath path, Object value) {
+		super(ExpressionParserTreeConstants.JJTGREATER);
+		jjtAddChild(path, 0);
+		jjtAddChild(new ASTScalar(value), 1);
+		connectChildren();
+	}
 
-        Object o1 = evaluateChild(0, o);
-        Object o2 = evaluateChild(1, o);
-        Integer c = Evaluator.evaluator(o1).compare(o1, o2);
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
 
-        return c != null && c > 0 ? Boolean.TRUE : Boolean.FALSE;
-    }
+		Object o1 = evaluateChild(0, o);
+		Object o2 = evaluateChild(1, o);
+		Integer c = Evaluator.evaluator(o1).compare(o1, o2);
 
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTGreater(id);
-    }
+		return c != null && c > 0 ? Boolean.TRUE : Boolean.FALSE;
+	}
 
-    @Override
-    protected String getExpressionOperator(int index) {
-        return ">";
-    }
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTGreater(id);
+	}
 
-    @Override
-    public int getType() {
-        return Expression.GREATER_THAN;
-    }
+	@Override
+	protected String getExpressionOperator(int index) {
+		return ">";
+	}
+
+	@Override
+	public int getType() {
+		return Expression.GREATER_THAN;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
index 36a6820..22d9e97 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTGreaterOrEqual.java
@@ -28,53 +28,55 @@ import org.apache.cayenne.exp.Expression;
  */
 public class ASTGreaterOrEqual extends ConditionNode {
 
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTGreaterOrEqual(int id) {
-        super(id);
-    }
-    
-    public ASTGreaterOrEqual() {
-        super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
-    }
+	private static final long serialVersionUID = -2926530926896058935L;
 
-    public ASTGreaterOrEqual(ASTPath path, Object value) {
-        super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
-        jjtAddChild(path, 0);
-        jjtAddChild(new ASTScalar(value), 1);
-        connectChildren();
-    }
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTGreaterOrEqual(int id) {
+		super(id);
+	}
 
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
+	public ASTGreaterOrEqual() {
+		super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
+	}
 
-        Object o1 = evaluateChild(0, o);
-        Object o2 = evaluateChild(1, o);
-        Integer c = Evaluator.evaluator(o1).compare(o1, o2);
+	public ASTGreaterOrEqual(ASTPath path, Object value) {
+		super(ExpressionParserTreeConstants.JJTGREATEROREQUAL);
+		jjtAddChild(path, 0);
+		jjtAddChild(new ASTScalar(value), 1);
+		connectChildren();
+	}
 
-        return c != null && c >= 0 ? Boolean.TRUE : Boolean.FALSE;
-    }
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
 
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTGreaterOrEqual(id);
-    }
+		Object o1 = evaluateChild(0, o);
+		Object o2 = evaluateChild(1, o);
+		Integer c = Evaluator.evaluator(o1).compare(o1, o2);
 
-    @Override
-    protected String getExpressionOperator(int index) {
-        return ">=";
-    }
+		return c != null && c >= 0 ? Boolean.TRUE : Boolean.FALSE;
+	}
 
-    @Override
-    public int getType() {
-        return Expression.GREATER_THAN_EQUAL_TO;
-    }
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTGreaterOrEqual(id);
+	}
+
+	@Override
+	protected String getExpressionOperator(int index) {
+		return ">=";
+	}
+
+	@Override
+	public int getType() {
+		return Expression.GREATER_THAN_EQUAL_TO;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
index 1d29ef1..10d7dc7 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTIn.java
@@ -30,99 +30,102 @@ import org.apache.commons.collections.Transformer;
  */
 public class ASTIn extends ConditionNode {
 
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTIn(int id) {
-        super(id);
-    }
-
-    public ASTIn() {
-        super(ExpressionParserTreeConstants.JJTIN);
-    }
-
-    public ASTIn(ASTPath path, ASTList list) {
-        super(ExpressionParserTreeConstants.JJTIN);
-        jjtAddChild(path, 0);
-        jjtAddChild(list, 1);
-        connectChildren();
-    }
-
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
-
-        Object o1 = evaluateChild(0, o);
-        // TODO: what if there's a NULL inside IN list? 
-        // e.g. ASTEqual evals as "NULL == NULL"
-        if (o1 == null) {
-            return Boolean.FALSE;
-        }
-
-        Object[] objects = (Object[]) evaluateChild(1, o);
-        if (objects == null) {
-            return Boolean.FALSE;
-        }
-
-        int size = objects.length;
-        for (int i = 0; i < size; i++) {
-            if (objects[i] != null) {
-                if (o1 instanceof Collection) {
-                    // handle the case where we have a collection of objects
-                    for (Object obj : (Collection) o1) {
-                        if (Evaluator.evaluator(obj).eq(obj, objects[i])) {
-                            return Boolean.TRUE;
-                        }
-                    }
-                } else {
-                    if (Evaluator.evaluator(o1).eq(o1, objects[i])) {
-                        return Boolean.TRUE;
-                    }
-                }
-            }
-        }
-
-        return Boolean.FALSE;
-    }
-
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTIn(id);
-    }
-
-    @Override
-    protected String getExpressionOperator(int index) {
-        return "in";
-    }
-
-    @Override
-    public int getType() {
-        return Expression.IN;
-    }
-
-    @Override
-    protected Object transformExpression(Transformer transformer) {
-        Object transformed = super.transformExpression(transformer);
-
-        // transform empty ASTIn to ASTFalse
-        if (transformed instanceof ASTIn) {
-            ASTIn exp = (ASTIn) transformed;
-            if (exp.jjtGetNumChildren() == 2) {
-                ASTList list = (ASTList) exp.jjtGetChild(1);
-                Object[] objects = (Object[]) list.evaluate(null);
-                if (objects.length == 0) {
-                    transformed = new ASTFalse();
-                }
-            }
-        }
-
-        return transformed;
-    }
+	private static final long serialVersionUID = -211084571117172965L;
+
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTIn(int id) {
+		super(id);
+	}
+
+	public ASTIn() {
+		super(ExpressionParserTreeConstants.JJTIN);
+	}
+
+	public ASTIn(ASTPath path, ASTList list) {
+		super(ExpressionParserTreeConstants.JJTIN);
+		jjtAddChild(path, 0);
+		jjtAddChild(list, 1);
+		connectChildren();
+	}
+
+	@SuppressWarnings("rawtypes")
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
+
+		Object o1 = evaluateChild(0, o);
+		// TODO: what if there's a NULL inside IN list?
+		// e.g. ASTEqual evals as "NULL == NULL"
+		if (o1 == null) {
+			return Boolean.FALSE;
+		}
+
+		Object[] objects = (Object[]) evaluateChild(1, o);
+		if (objects == null) {
+			return Boolean.FALSE;
+		}
+
+		int size = objects.length;
+		for (int i = 0; i < size; i++) {
+			if (objects[i] != null) {
+				if (o1 instanceof Collection) {
+					// handle the case where we have a collection of objects
+					for (Object obj : (Collection) o1) {
+						if (Evaluator.evaluator(obj).eq(obj, objects[i])) {
+							return Boolean.TRUE;
+						}
+					}
+				} else {
+					if (Evaluator.evaluator(o1).eq(o1, objects[i])) {
+						return Boolean.TRUE;
+					}
+				}
+			}
+		}
+
+		return Boolean.FALSE;
+	}
+
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTIn(id);
+	}
+
+	@Override
+	protected String getExpressionOperator(int index) {
+		return "in";
+	}
+
+	@Override
+	public int getType() {
+		return Expression.IN;
+	}
+
+	@Override
+	protected Object transformExpression(Transformer transformer) {
+		Object transformed = super.transformExpression(transformer);
+
+		// transform empty ASTIn to ASTFalse
+		if (transformed instanceof ASTIn) {
+			ASTIn exp = (ASTIn) transformed;
+			if (exp.jjtGetNumChildren() == 2) {
+				ASTList list = (ASTList) exp.jjtGetChild(1);
+				Object[] objects = (Object[]) list.evaluate(null);
+				if (objects.length == 0) {
+					transformed = new ASTFalse();
+				}
+			}
+		}
+
+		return transformed;
+	}
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
index 4494620..5a44f62 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLess.java
@@ -27,53 +27,56 @@ import org.apache.cayenne.exp.Expression;
  * @since 1.1
  */
 public class ASTLess extends ConditionNode {
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTLess(int id) {
-        super(id);
-    }
 
-    public ASTLess() {
-        super(ExpressionParserTreeConstants.JJTLESS);
-    }
+	private static final long serialVersionUID = -3846841914847489596L;
 
-    public ASTLess(ASTPath path, Object value) {
-        super(ExpressionParserTreeConstants.JJTLESS);
-        jjtAddChild(path, 0);
-        jjtAddChild(new ASTScalar(value), 1);
-        connectChildren();
-    }
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTLess(int id) {
+		super(id);
+	}
 
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
+	public ASTLess() {
+		super(ExpressionParserTreeConstants.JJTLESS);
+	}
 
-        Object o1 = evaluateChild(0, o);
-        Object o2 = evaluateChild(1, o);
-        Integer c = Evaluator.evaluator(o1).compare(o1, o2);
+	public ASTLess(ASTPath path, Object value) {
+		super(ExpressionParserTreeConstants.JJTLESS);
+		jjtAddChild(path, 0);
+		jjtAddChild(new ASTScalar(value), 1);
+		connectChildren();
+	}
 
-        return c != null && c < 0 ? Boolean.TRUE : Boolean.FALSE;
-    }
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
 
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTLess(id);
-    }
+		Object o1 = evaluateChild(0, o);
+		Object o2 = evaluateChild(1, o);
+		Integer c = Evaluator.evaluator(o1).compare(o1, o2);
 
-    @Override
-    protected String getExpressionOperator(int index) {
-        return "<";
-    }
+		return c != null && c < 0 ? Boolean.TRUE : Boolean.FALSE;
+	}
 
-    @Override
-    public int getType() {
-        return Expression.LESS_THAN;
-    }
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTLess(id);
+	}
+
+	@Override
+	protected String getExpressionOperator(int index) {
+		return "<";
+	}
+
+	@Override
+	public int getType() {
+		return Expression.LESS_THAN;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
index 02fa9d0..9065631 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTLessOrEqual.java
@@ -28,53 +28,55 @@ import org.apache.cayenne.exp.Expression;
  */
 public class ASTLessOrEqual extends ConditionNode {
 
-    /**
-     * Constructor used by expression parser. Do not invoke directly.
-     */
-    ASTLessOrEqual(int id) {
-        super(id);
-    }
+	private static final long serialVersionUID = -710886570064202360L;
 
-    public ASTLessOrEqual() {
-        super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
-    }
+	/**
+	 * Constructor used by expression parser. Do not invoke directly.
+	 */
+	ASTLessOrEqual(int id) {
+		super(id);
+	}
 
-    public ASTLessOrEqual(ASTPath path, Object value) {
-        super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
-        jjtAddChild(path, 0);
-        jjtAddChild(new ASTScalar(value), 1);
-        connectChildren();
-    }
+	public ASTLessOrEqual() {
+		super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
+	}
 
-    @Override
-    protected Object evaluateNode(Object o) throws Exception {
-        int len = jjtGetNumChildren();
-        if (len != 2) {
-            return Boolean.FALSE;
-        }
+	public ASTLessOrEqual(ASTPath path, Object value) {
+		super(ExpressionParserTreeConstants.JJTLESSOREQUAL);
+		jjtAddChild(path, 0);
+		jjtAddChild(new ASTScalar(value), 1);
+		connectChildren();
+	}
 
-        Object o1 = evaluateChild(0, o);
-        Object o2 = evaluateChild(1, o);
-        Integer c = Evaluator.evaluator(o1).compare(o1, o2);
+	@Override
+	protected Object evaluateNode(Object o) throws Exception {
+		int len = jjtGetNumChildren();
+		if (len != 2) {
+			return Boolean.FALSE;
+		}
 
-        return c != null && c <= 0 ? Boolean.TRUE : Boolean.FALSE;
-    }
+		Object o1 = evaluateChild(0, o);
+		Object o2 = evaluateChild(1, o);
+		Integer c = Evaluator.evaluator(o1).compare(o1, o2);
 
-    /**
-     * Creates a copy of this expression node, without copying children.
-     */
-    @Override
-    public Expression shallowCopy() {
-        return new ASTLessOrEqual(id);
-    }
+		return c != null && c <= 0 ? Boolean.TRUE : Boolean.FALSE;
+	}
 
-    @Override
-    protected String getExpressionOperator(int index) {
-        return "<=";
-    }
+	/**
+	 * Creates a copy of this expression node, without copying children.
+	 */
+	@Override
+	public Expression shallowCopy() {
+		return new ASTLessOrEqual(id);
+	}
 
-    @Override
-    public int getType() {
-        return Expression.LESS_THAN_EQUAL_TO;
-    }
+	@Override
+	protected String getExpressionOperator(int index) {
+		return "<=";
+	}
+
+	@Override
+	public int getType() {
+		return Expression.LESS_THAN_EQUAL_TO;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTInTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTInTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTInTest.java
new file mode 100644
index 0000000..fc5edb4
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTInTest.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.apache.cayenne.exp.parser;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.testdo.testmap.Painting;
+import org.junit.Test;
+
+public class ASTInTest {
+
+	@Test
+	public void testEvaluate() {
+		Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] { new BigDecimal("10"),
+				new BigDecimal("20") }));
+
+		Expression notIn = new ASTNotIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
+				new BigDecimal("10"), new BigDecimal("20") }));
+
+		Painting noMatch1 = new Painting();
+		noMatch1.setEstimatedPrice(new BigDecimal("21"));
+		assertFalse(in.match(noMatch1));
+		assertTrue(notIn.match(noMatch1));
+
+		Painting noMatch2 = new Painting();
+		noMatch2.setEstimatedPrice(new BigDecimal("11"));
+		assertFalse("Failed: " + in, in.match(noMatch2));
+		assertTrue("Failed: " + notIn, notIn.match(noMatch2));
+
+		Painting match1 = new Painting();
+		match1.setEstimatedPrice(new BigDecimal("20"));
+		assertTrue(in.match(match1));
+		assertFalse(notIn.match(match1));
+
+		Painting match2 = new Painting();
+		match2.setEstimatedPrice(new BigDecimal("10"));
+		assertTrue("Failed: " + in, in.match(match2));
+		assertFalse("Failed: " + notIn, notIn.match(match2));
+	}
+
+	@Test
+	public void testEvaluate_Null() {
+		Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] { new BigDecimal("10"),
+				new BigDecimal("20") }));
+		Expression notIn = new ASTNotIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
+				new BigDecimal("10"), new BigDecimal("20") }));
+
+		Painting noMatch = new Painting();
+		assertFalse(in.match(noMatch));
+		assertFalse(notIn.match(noMatch));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/5faca1c3/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
index 2eaf907..5cd107e 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ExpressionEvaluateInMemoryTest.java
@@ -26,9 +26,9 @@ import java.math.BigDecimal;
 
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.testdo.testmap.Artist;
-import org.apache.cayenne.testdo.testmap.Painting;
 import org.junit.Test;
 
+// TODO: split it between AST* unit tests (partially done already)
 public class ExpressionEvaluateInMemoryTest {
 
 	@Test
@@ -82,47 +82,6 @@ public class ExpressionEvaluateInMemoryTest {
 	}
 
 	@Test
-	public void testEvaluateIN() {
-		Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] { new BigDecimal("10"),
-				new BigDecimal("20") }));
-
-		Expression notIn = new ASTNotIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
-				new BigDecimal("10"), new BigDecimal("20") }));
-
-		Painting noMatch1 = new Painting();
-		noMatch1.setEstimatedPrice(new BigDecimal("21"));
-		assertFalse(in.match(noMatch1));
-		assertTrue(notIn.match(noMatch1));
-
-		Painting noMatch2 = new Painting();
-		noMatch2.setEstimatedPrice(new BigDecimal("11"));
-		assertFalse("Failed: " + in, in.match(noMatch2));
-		assertTrue("Failed: " + notIn, notIn.match(noMatch2));
-
-		Painting match1 = new Painting();
-		match1.setEstimatedPrice(new BigDecimal("20"));
-		assertTrue(in.match(match1));
-		assertFalse(notIn.match(match1));
-
-		Painting match2 = new Painting();
-		match2.setEstimatedPrice(new BigDecimal("10"));
-		assertTrue("Failed: " + in, in.match(match2));
-		assertFalse("Failed: " + notIn, notIn.match(match2));
-	}
-
-	@Test
-	public void testEvaluateIN_Null() {
-		Expression in = new ASTIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] { new BigDecimal("10"),
-				new BigDecimal("20") }));
-		Expression notIn = new ASTNotIn(new ASTObjPath("estimatedPrice"), new ASTList(new Object[] {
-				new BigDecimal("10"), new BigDecimal("20") }));
-
-		Painting noMatch = new Painting();
-		assertFalse(in.match(noMatch));
-		assertFalse(notIn.match(noMatch));
-	}
-
-	@Test
 	public void testEvaluateADD() {
 		Expression add = new ASTAdd(new Object[] { new Integer(1), new Double(5.5) });
 		assertEquals(6.5, ((Number) add.evaluate(null)).doubleValue(), 0.0001);