Author: aadamchik
Date: Mon Mar 18 19:30:55 2013
New Revision: 1457927

URL: http://svn.apache.org/r1457927
Log:
CAY-1803  Define toString() in path expressions

Modified:
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/Expression.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTDbPath.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTList.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTObjPath.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTScalar.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
    
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/SimpleNode.java

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/Expression.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/Expression.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/Expression.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/Expression.java
 Mon Mar 18 19:30:55 2013
@@ -19,17 +19,18 @@
 
 package org.apache.cayenne.exp;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.Serializable;
 import java.io.StringReader;
-import java.io.StringWriter;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.exp.parser.ASTScalar;
 import org.apache.cayenne.exp.parser.ExpressionParser;
 import org.apache.cayenne.exp.parser.ExpressionParserTokenManager;
@@ -47,8 +48,8 @@ import org.apache.commons.collections.Tr
 public abstract class Expression implements Serializable, XMLSerializable {
 
     /**
-     * A value that a Transformer might return to indicate that a node has to 
be pruned
-     * from the expression during the transformation.
+     * A value that a Transformer might return to indicate that a node has to 
be
+     * pruned from the expression during the transformation.
      * 
      * @since 1.2
      */
@@ -76,35 +77,37 @@ public abstract class Expression impleme
     public static final int FALSE = 22;
 
     /**
-     * Expression describes a path relative to an ObjEntity. OBJ_PATH 
expression is
-     * resolved relative to some root ObjEntity. Path expression components 
are separated
-     * by "." (dot). Path can point to either one of these:
+     * Expression describes a path relative to an ObjEntity. OBJ_PATH 
expression
+     * is resolved relative to some root ObjEntity. Path expression components
+     * are separated by "." (dot). Path can point to either one of these:
      * <ul>
-     * <li><i>An attribute of root ObjEntity.</i> For entity Gallery OBJ_PATH 
expression
-     * "galleryName" will point to ObjAttribute "galleryName"
+     * <li><i>An attribute of root ObjEntity.</i> For entity Gallery OBJ_PATH
+     * expression "galleryName" will point to ObjAttribute "galleryName"
      * <li><i>Another ObjEntity related to root ObjEntity via a chain of
-     * relationships.</i> For entity Gallery OBJ_PATH expression 
"paintingArray.toArtist"
-     * will point to ObjEntity "Artist"
-     * <li><i>ObjAttribute of another ObjEntity related to root ObjEntity via 
a chain of
      * relationships.</i> For entity Gallery OBJ_PATH expression
-     * "paintingArray.toArtist.artistName" will point to ObjAttribute 
"artistName"
+     * "paintingArray.toArtist" will point to ObjEntity "Artist"
+     * <li><i>ObjAttribute of another ObjEntity related to root ObjEntity via a
+     * chain of relationships.</i> For entity Gallery OBJ_PATH expression
+     * "paintingArray.toArtist.artistName" will point to ObjAttribute
+     * "artistName"
      * </ul>
      */
     public static final int OBJ_PATH = 26;
 
     /**
-     * Expression describes a path relative to a DbEntity. DB_PATH expression 
is resolved
-     * relative to some root DbEntity. Path expression components are 
separated by "."
-     * (dot). Path can point to either one of these:
+     * Expression describes a path relative to a DbEntity. DB_PATH expression 
is
+     * resolved relative to some root DbEntity. Path expression components are
+     * separated by "." (dot). Path can point to either one of these:
      * <ul>
-     * <li><i>An attribute of root DbEntity.</i> For entity GALLERY, DB_PATH 
expression
-     * "GALLERY_NAME" will point to a DbAttribute "GALLERY_NAME".</li>
-     * <li><i>Another DbEntity related to root DbEntity via a chain of 
relationships.</i>
-     * For entity GALLERY DB_PATH expression "paintingArray.toArtist" will 
point to
-     * DbEntity "ARTIST".</li>
-     * <li><i>DbAttribute of another ObjEntity related to root DbEntity via a 
chain of
+     * <li><i>An attribute of root DbEntity.</i> For entity GALLERY, DB_PATH
+     * expression "GALLERY_NAME" will point to a DbAttribute 
"GALLERY_NAME".</li>
+     * <li><i>Another DbEntity related to root DbEntity via a chain of
      * relationships.</i> For entity GALLERY DB_PATH expression
-     * "paintingArray.toArtist.ARTIST_NAME" will point to DbAttribute 
"ARTIST_NAME".</li>
+     * "paintingArray.toArtist" will point to DbEntity "ARTIST".</li>
+     * <li><i>DbAttribute of another ObjEntity related to root DbEntity via a
+     * chain of relationships.</i> For entity GALLERY DB_PATH expression
+     * "paintingArray.toArtist.ARTIST_NAME" will point to DbAttribute
+     * "ARTIST_NAME".</li>
      * </ul>
      */
     public static final int DB_PATH = 27;
@@ -118,32 +121,32 @@ public abstract class Expression impleme
     public static final int NOT_IN = 36;
     public static final int NOT_LIKE = 37;
     public static final int NOT_LIKE_IGNORE_CASE = 38;
-    
+
     /**
      * @since 3.1
      */
     public static final int BITWISE_NOT = 39;
-    
+
     /**
      * @since 3.1
      */
     public static final int BITWISE_AND = 40;
-    
+
     /**
      * @since 3.1
      */
     public static final int BITWISE_OR = 41;
-    
+
     /**
      * @since 3.1
      */
     public static final int BITWISE_XOR = 42;
-    
+
     /**
      * @since 3.2
      */
     public static final int BITWISE_LEFT_SHIFT = 43;
-    
+
     /**
      * @since 3.2
      */
@@ -154,8 +157,8 @@ public abstract class Expression impleme
     protected int type;
 
     /**
-     * Parses string, converting it to Expression. If string does not 
represent a
-     * semantically correct expression, an ExpressionException is thrown.
+     * Parses string, converting it to Expression. If string does not represent
+     * a semantically correct expression, an ExpressionException is thrown.
      * 
      * @since 1.1
      */
@@ -166,11 +169,11 @@ public abstract class Expression impleme
         }
 
         // optimizing parser buffers per CAY-1667...
-        // adding 1 extra char to the buffer size above the String length, as 
otherwise
+        // adding 1 extra char to the buffer size above the String length, as
+        // otherwise
         // resizing still occurs at the end of the stream
-        int bufferSize = expressionString.length() > PARSE_BUFFER_MAX_SIZE
-                ? PARSE_BUFFER_MAX_SIZE
-                : expressionString.length() + 1;
+        int bufferSize = expressionString.length() > PARSE_BUFFER_MAX_SIZE ? 
PARSE_BUFFER_MAX_SIZE : expressionString
+                .length() + 1;
         Reader reader = new StringReader(expressionString);
         JavaCharStream stream = new JavaCharStream(reader, 1, 1, bufferSize);
         ExpressionParserTokenManager tm = new 
ExpressionParserTokenManager(stream);
@@ -178,26 +181,24 @@ public abstract class Expression impleme
 
         try {
             return parser.expression();
-        }
-        catch (ParseException ex) {
+        } catch (ParseException ex) {
 
             // can be null
             String message = ex.getMessage();
             throw new ExpressionException(message != null ? message : "", ex);
-        }
-        catch (Throwable th) {
+        } catch (Throwable th) {
             // can be null
             String message = th.getMessage();
-            
+
             // another common error is TokenManagerError
             throw new ExpressionException(message != null ? message : "", th);
         }
     }
 
     /**
-     * Returns a map of path aliases for this expression. It returns a 
non-empty map only
-     * if this is a path expression and the aliases are known at the 
expression creation
-     * time. Otherwise an empty map is returned.
+     * Returns a map of path aliases for this expression. It returns a 
non-empty
+     * map only if this is a path expression and the aliases are known at the
+     * expression creation time. Otherwise an empty map is returned.
      * 
      * @since 3.0
      */
@@ -208,48 +209,48 @@ public abstract class Expression impleme
      */
     public String expName() {
         switch (type) {
-            case AND:
-                return "AND";
-            case OR:
-                return "OR";
-            case NOT:
-                return "NOT";
-            case EQUAL_TO:
-                return "=";
-            case NOT_EQUAL_TO:
-                return "<>";
-            case LESS_THAN:
-                return "<";
-            case LESS_THAN_EQUAL_TO:
-                return "<=";
-            case GREATER_THAN:
-                return ">";
-            case GREATER_THAN_EQUAL_TO:
-                return ">=";
-            case BETWEEN:
-                return "BETWEEN";
-            case IN:
-                return "IN";
-            case LIKE:
-                return "LIKE";
-            case LIKE_IGNORE_CASE:
-                return "LIKE_IGNORE_CASE";
-            case OBJ_PATH:
-                return "OBJ_PATH";
-            case DB_PATH:
-                return "DB_PATH";
-            case LIST:
-                return "LIST";
-            case NOT_BETWEEN:
-                return "NOT BETWEEN";
-            case NOT_IN:
-                return "NOT IN";
-            case NOT_LIKE:
-                return "NOT LIKE";
-            case NOT_LIKE_IGNORE_CASE:
-                return "NOT LIKE IGNORE CASE";
-            default:
-                return "other";
+        case AND:
+            return "AND";
+        case OR:
+            return "OR";
+        case NOT:
+            return "NOT";
+        case EQUAL_TO:
+            return "=";
+        case NOT_EQUAL_TO:
+            return "<>";
+        case LESS_THAN:
+            return "<";
+        case LESS_THAN_EQUAL_TO:
+            return "<=";
+        case GREATER_THAN:
+            return ">";
+        case GREATER_THAN_EQUAL_TO:
+            return ">=";
+        case BETWEEN:
+            return "BETWEEN";
+        case IN:
+            return "IN";
+        case LIKE:
+            return "LIKE";
+        case LIKE_IGNORE_CASE:
+            return "LIKE_IGNORE_CASE";
+        case OBJ_PATH:
+            return "OBJ_PATH";
+        case DB_PATH:
+            return "DB_PATH";
+        case LIST:
+            return "LIST";
+        case NOT_BETWEEN:
+            return "NOT BETWEEN";
+        case NOT_IN:
+            return "NOT IN";
+        case NOT_LIKE:
+            return "NOT LIKE";
+        case NOT_LIKE_IGNORE_CASE:
+            return "NOT LIKE IGNORE CASE";
+        default:
+            return "other";
         }
     }
 
@@ -277,8 +278,8 @@ public abstract class Expression impleme
     }
 
     /**
-     * Returns a type of expression. Most common types are defined as public 
static fields
-     * of this interface.
+     * Returns a type of expression. Most common types are defined as public
+     * static fields of this interface.
      */
     public int getType() {
         return type;
@@ -296,26 +297,28 @@ public abstract class Expression impleme
     }
 
     /**
-     * Creates and returns a new Expression instance using this expression as 
a prototype.
-     * All ExpressionParam operands are substituted with the values in the
-     * <code>params</code> map.
+     * Creates and returns a new Expression instance using this expression as a
+     * prototype. All ExpressionParam operands are substituted with the values
+     * in the <code>params</code> map.
      * <p>
-     * <i>Null values in the <code>params</code> map should be explicitly 
created in the
-     * map for the corresponding key. </i>
+     * <i>Null values in the <code>params</code> map should be explicitly
+     * created in the map for the corresponding key. </i>
      * </p>
      * 
-     * @param parameters a map of parameters, with each key being a string 
name of an
-     *            expression parameter, and value being the value that should 
be used in
-     *            the final expression.
-     * @param pruneMissing If <code>true</code>, subexpressions that rely on 
missing
-     *            parameters will be pruned from the resulting tree. If 
<code>false</code>
-     *            , any missing values will generate an exception.
-     * @return Expression resulting from the substitution of parameters with 
real values,
-     *         or null if the whole expression was pruned, due to the missing 
parameters.
-     */
-    public Expression expWithParameters(
-            final Map<String, ?> parameters,
-            final boolean pruneMissing) {
+     * @param parameters
+     *            a map of parameters, with each key being a string name of an
+     *            expression parameter, and value being the value that should 
be
+     *            used in the final expression.
+     * @param pruneMissing
+     *            If <code>true</code>, subexpressions that rely on missing
+     *            parameters will be pruned from the resulting tree. If
+     *            <code>false</code> , any missing values will generate an
+     *            exception.
+     * @return Expression resulting from the substitution of parameters with
+     *         real values, or null if the whole expression was pruned, due to
+     *         the missing parameters.
+     */
+    public Expression expWithParameters(final Map<String, ?> parameters, final 
boolean pruneMissing) {
 
         // create transformer for named parameters
         Transformer transformer = new Transformer() {
@@ -329,21 +332,17 @@ public abstract class Expression impleme
                 if (!parameters.containsKey(name)) {
                     if (pruneMissing) {
                         return PRUNED_NODE;
+                    } else {
+                        throw new ExpressionException("Missing required 
parameter: $" + name);
                     }
-                    else {
-                        throw new ExpressionException("Missing required 
parameter: $"
-                                + name);
-                    }
-                }
-                else {
+                } else {
                     Object value = parameters.get(name);
 
                     // wrap lists (for now); also support null parameters
-                    // TODO: andrus 8/14/2007 - shouldn't we also wrap 
non-null object
+                    // TODO: andrus 8/14/2007 - shouldn't we also wrap non-null
+                    // object
                     // values in ASTScalars?
-                    return (value != null)
-                            ? ExpressionFactory.wrapPathOperand(value)
-                            : new ASTScalar(null);
+                    return (value != null) ? 
ExpressionFactory.wrapPathOperand(value) : new ASTScalar(null);
                 }
             }
         };
@@ -352,18 +351,18 @@ public abstract class Expression impleme
     }
 
     /**
-     * Creates a new expression that joins this object with another 
expression, using
-     * specified join type. It is very useful for incrementally building 
chained
-     * expressions, like long AND or OR statements.
+     * Creates a new expression that joins this object with another expression,
+     * using specified join type. It is very useful for incrementally building
+     * chained expressions, like long AND or OR statements.
      */
     public Expression joinExp(int type, Expression exp) {
         return joinExp(type, exp, new Expression[0]);
     }
-    
+
     /**
-     * Creates a new expression that joins this object with other expressions, 
using
-     * specified join type. It is very useful for incrementally building 
chained
-     * expressions, like long AND or OR statements.
+     * Creates a new expression that joins this object with other expressions,
+     * using specified join type. It is very useful for incrementally building
+     * chained expressions, like long AND or OR statements.
      * 
      * @since 3.2
      */
@@ -373,7 +372,7 @@ public abstract class Expression impleme
         join.setOperand(1, exp);
         for (int i = 0; i < expressions.length; i++) {
             Expression expressionInArray = expressions[i];
-            join.setOperand(2+i, expressionInArray);
+            join.setOperand(2 + i, expressionInArray);
         }
         join.flattenTree();
         return join;
@@ -394,7 +393,7 @@ public abstract class Expression impleme
     public Expression andExp(Expression exp, Expression... expressions) {
         return joinExp(Expression.AND, exp, expressions);
     }
-    
+
     /**
      * Chains this expression with another expression using "or".
      */
@@ -410,7 +409,7 @@ public abstract class Expression impleme
     public Expression orExp(Expression exp, Expression... expressions) {
         return joinExp(Expression.OR, exp, expressions);
     }
-    
+
     /**
      * Returns a logical NOT of current expression.
      * 
@@ -419,37 +418,42 @@ public abstract class Expression impleme
     public abstract Expression notExp();
 
     /**
-     * Returns a count of operands of this expression. In real life there are 
unary (count
-     * == 1), binary (count == 2) and ternary (count == 3) expressions.
+     * Returns a count of operands of this expression. In real life there are
+     * unary (count == 1), binary (count == 2) and ternary (count == 3)
+     * expressions.
      */
     public abstract int getOperandCount();
 
     /**
-     * Returns a value of operand at <code>index</code>. Operand indexing 
starts at 0.
+     * Returns a value of operand at <code>index</code>. Operand indexing 
starts
+     * at 0.
      */
     public abstract Object getOperand(int index);
 
     /**
-     * Sets a value of operand at <code>index</code>. Operand indexing starts 
at 0.
+     * Sets a value of operand at <code>index</code>. Operand indexing starts 
at
+     * 0.
      */
     public abstract void setOperand(int index, Object value);
 
     /**
-     * Calculates expression value with object as a context for path 
expressions.
+     * Calculates expression value with object as a context for path
+     * expressions.
      * 
      * @since 1.1
      */
     public abstract Object evaluate(Object o);
 
     /**
-     * Calculates expression boolean value with object as a context for path 
expressions.
+     * Calculates expression boolean value with object as a context for path
+     * expressions.
      * 
      * @since 1.1
      */
     public boolean match(Object o) {
         return ConversionUtil.toBoolean(evaluate(o));
     }
-    
+
     /**
      * Returns the first object in the list that matches the expression.
      * 
@@ -477,8 +481,8 @@ public abstract class Expression impleme
     }
 
     /**
-     * Adds objects matching this expression from the source collection to the 
target
-     * collection.
+     * Adds objects matching this expression from the source collection to the
+     * target collection.
      * 
      * @since 1.1
      */
@@ -509,25 +513,25 @@ public abstract class Expression impleme
     public abstract Expression shallowCopy();
 
     /**
-     * Returns true if this node should be pruned from expression tree in the 
event a
-     * child is removed.
+     * Returns true if this node should be pruned from expression tree in the
+     * event a child is removed.
      * 
      * @since 1.1
      */
     protected abstract boolean pruneNodeForPrunedChild(Object prunedChild);
 
     /**
-     * Restructures expression to make sure that there are no children of the 
same type as
-     * this expression.
+     * Restructures expression to make sure that there are no children of the
+     * same type as this expression.
      * 
      * @since 1.1
      */
     protected abstract void flattenTree();
 
     /**
-     * Traverses itself and child expressions, notifying visitor via callback 
methods as
-     * it goes. This is an Expression-specific implementation of the "Visitor" 
design
-     * pattern.
+     * Traverses itself and child expressions, notifying visitor via callback
+     * methods as it goes. This is an Expression-specific implementation of the
+     * "Visitor" design pattern.
      * 
      * @since 1.1
      */
@@ -540,8 +544,8 @@ public abstract class Expression impleme
     }
 
     /**
-     * Traverses itself and child expressions, notifying visitor via callback 
methods as
-     * it goes.
+     * Traverses itself and child expressions, notifying visitor via callback
+     * methods as it goes.
      * 
      * @since 1.1
      */
@@ -557,8 +561,7 @@ public abstract class Expression impleme
             if (child instanceof Expression) {
                 Expression childExp = (Expression) child;
                 childExp.traverse(this, visitor);
-            }
-            else {
+            } else {
                 visitor.objectNode(child, this);
             }
 
@@ -569,14 +572,14 @@ public abstract class Expression impleme
     }
 
     /**
-     * Creates a transformed copy of this expression, applying transformation 
provided by
-     * Transformer to all its nodes. Null transformer will result in an 
identical deep
-     * copy of this expression.
+     * Creates a transformed copy of this expression, applying transformation
+     * provided by Transformer to all its nodes. Null transformer will result 
in
+     * an identical deep copy of this expression.
      * <p>
-     * To force a node and its children to be pruned from the copy, 
Transformer should
-     * return Expression.PRUNED_NODE. Otherwise an expectation is that if a 
node is an
-     * Expression it must be transformed to null or another Expression. Any 
other object
-     * type would result in a ExpressionException.
+     * To force a node and its children to be pruned from the copy, Transformer
+     * should return Expression.PRUNED_NODE. Otherwise an expectation is that 
if
+     * a node is an Expression it must be transformed to null or another
+     * Expression. Any other object type would result in a ExpressionException.
      * 
      * @since 1.1
      */
@@ -585,8 +588,7 @@ public abstract class Expression impleme
 
         if (transformed == PRUNED_NODE || transformed == null) {
             return null;
-        }
-        else if (transformed instanceof Expression) {
+        } else if (transformed instanceof Expression) {
             return (Expression) transformed;
         }
 
@@ -594,7 +596,8 @@ public abstract class Expression impleme
     }
 
     /**
-     * A recursive method called from "transform" to do the actual 
transformation.
+     * A recursive method called from "transform" to do the actual
+     * transformation.
      * 
      * @return null, Expression.PRUNED_NODE or transformed expression.
      * @since 1.2
@@ -607,17 +610,15 @@ public abstract class Expression impleme
             Object transformedChild;
 
             if (operand instanceof Expression) {
-                transformedChild = ((Expression) operand)
-                        .transformExpression(transformer);
-            }
-            else if (transformer != null) {
+                transformedChild = ((Expression) 
operand).transformExpression(transformer);
+            } else if (transformer != null) {
                 transformedChild = transformer.transform(operand);
-            }
-            else {
+            } else {
                 transformedChild = operand;
             }
 
-            // prune null children only if there is a transformer and it 
indicated so
+            // prune null children only if there is a transformer and it
+            // indicated so
             boolean prune = transformer != null && transformedChild == 
PRUNED_NODE;
 
             if (!prune) {
@@ -642,44 +643,74 @@ public abstract class Expression impleme
      */
     public void encodeAsXML(XMLEncoder encoder) {
         encoder.print("<![CDATA[");
-        encodeAsString(encoder.getPrintWriter());
+        try {
+            appendAsString(encoder.getPrintWriter());
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IO exception 
appending to PrintWriter", e);
+        }
         encoder.print("]]>");
     }
 
     /**
-     * Stores a String representation of Expression using a provided 
PrintWriter.
+     * Stores a String representation of Expression using a provided
+     * PrintWriter.
      * 
      * @since 1.1
+     * @deprecated since 3.2 use {@link #appendAsString(Appendable)}.
      */
+    @Deprecated
     public abstract void encodeAsString(PrintWriter pw);
 
     /**
-     * Stores a String representation of Expression as EJBQL using a provided 
PrintWriter.
-     * DB path expressions produce non-standard EJBQL path expressions.
+     * Appends own content as a String to the provided Appendable.
+     * 
+     * @since 3.2
+     * @throws IOException
+     */
+    public abstract void appendAsString(Appendable out) throws IOException;
+
+    /**
+     * Stores a String representation of Expression as EJBQL using a provided
+     * PrintWriter. DB path expressions produce non-standard EJBQL path
+     * expressions.
      * 
      * @since 3.0
+     * @deprecated since 3.2 use {@link #appendAsEJBQL(Appendable, String)}
      */
+    @Deprecated
     public abstract void encodeAsEJBQL(PrintWriter pw, String rootId);
 
+    /**
+     * Stores a String representation of Expression as EJBQL using a provided
+     * Appendable. DB path expressions produce non-standard EJBQL path
+     * expressions.
+     * 
+     * @since 3.2
+     * @throws IOException
+     */
+    public abstract void appendAsEJBQL(Appendable out, String rootId) throws 
IOException;
+
     @Override
     public String toString() {
-        StringWriter buffer = new StringWriter();
-        PrintWriter pw = new PrintWriter(buffer);
-        encodeAsString(pw);
-        pw.close();
-        buffer.flush();
-        return buffer.toString();
+        StringBuilder out = new StringBuilder();
+        try {
+            appendAsString(out);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IO exception 
appending to StringBuilder", e);
+        }
+        return out.toString();
     }
 
     /**
      * @since 3.0
      */
     public String toEJBQL(String rootId) {
-        StringWriter buffer = new StringWriter();
-        PrintWriter pw = new PrintWriter(buffer);
-        encodeAsEJBQL(pw, rootId);
-        pw.close();
-        buffer.flush();
-        return buffer.toString();
+        StringBuilder out = new StringBuilder();
+        try {
+            appendAsEJBQL(out, rootId);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IO exception 
appending to StringBuilder", e);
+        }
+        return out.toString();
     }
 }

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTDbPath.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTDbPath.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTDbPath.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTDbPath.java
 Mon Mar 18 19:30:55 2013
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.exp.parser;
 
-import java.io.PrintWriter;
+import java.io.IOException;
 import java.util.Map;
 
 import org.apache.cayenne.ObjectId;
@@ -88,31 +88,24 @@ public class ASTDbPath extends ASTPath {
         return copy;
     }
 
-    @Override
-    public void encodeAsString(PrintWriter pw) {
-        pw.print(DB_PREFIX);
-        pw.print(path);
-    }
-
     /**
-     * @since 3.0
+     * @since 3.2
      */
     @Override
-    public void encodeAsEJBQL(PrintWriter pw, String rootId) {
+    public void appendAsEJBQL(Appendable out, String rootId) throws 
IOException {
         // warning: non-standard EJBQL...
-        pw.print(DB_PREFIX);
-        pw.print(rootId);
-        pw.print('.');
-        pw.print(path);
+        out.append(DB_PREFIX);
+        out.append(rootId);
+        out.append('.');
+        out.append(path);
     }
 
     /**
      * @since 3.2
      */
     @Override
-    public String toString() {
-        // shouldn't rely on super, see CAY-1803
-        return DB_PREFIX + path;
+    public void appendAsString(Appendable out) throws IOException {
+        out.append(DB_PREFIX).append(path);
     }
 
     @Override

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTList.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTList.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTList.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTList.java
 Mon Mar 18 19:30:55 2013
@@ -19,12 +19,14 @@
 
 package org.apache.cayenne.exp.parser;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.exp.Expression;
 
 /**
@@ -90,56 +92,80 @@ public class ASTList extends SimpleNode 
         return ",";
     }
 
+    /**
+     * @since 3.2
+     */
     @Override
-    public void encodeAsString(PrintWriter pw) {
-        pw.print('(');
+    public void appendAsString(Appendable out) throws IOException {
+
+        out.append('(');
 
         if ((values != null) && (values.length > 0)) {
             for (int i = 0; i < values.length; ++i) {
                 if (i > 0) {
-                    pw.print(getExpressionOperator(i));
-                    pw.print(' ');
+                    out.append(getExpressionOperator(i));
+                    out.append(' ');
                 }
 
                 if (values[i] instanceof Expression) {
-                    ((Expression) values[i]).encodeAsString(pw);
-                }
-                else {
-                    encodeScalarAsString(pw, values[i], '\"');
+                    ((Expression) values[i]).appendAsString(out);
+                } else {
+                    appendScalarAsString(out, values[i], '\"');
                 }
             }
         }
 
-        pw.print(')');
+        out.append(')');
     }
-    
+
     /**
-     * @since 3.0
+     * @deprecated since 3.2 use {@link #appendAsString(Appendable)}
      */
     @Override
-    public void encodeAsEJBQL(PrintWriter pw, String rootId) {
+    public void encodeAsString(PrintWriter pw) {
+        try {
+            appendAsString(pw);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IOException 
appending to PrintWriter", e);
+        }
+    }
+
+    @Override
+    public void appendAsEJBQL(Appendable out, String rootId) throws 
IOException {
+
         if (parent != null) {
-            pw.print("(");
+            out.append("(");
         }
 
         if ((values != null) && (values.length > 0)) {
             for (int i = 0; i < values.length; ++i) {
                 if (i > 0) {
-                    pw.print(getEJBQLExpressionOperator(i));
-                    pw.print(' ');
+                    out.append(getEJBQLExpressionOperator(i));
+                    out.append(' ');
                 }
 
                 if (values[i] == null) {
-                    pw.print("null");
-                }
-                else {
-                    SimpleNode.encodeScalarAsString(pw, values[i], '\'');
+                    out.append("null");
+                } else {
+                    SimpleNode.appendScalarAsString(out, values[i], '\'');
                 }
             }
         }
 
         if (parent != null) {
-            pw.print(')');
+            out.append(')');
+        }
+    }
+
+    /**
+     * @since 3.0
+     */
+    @Override
+    public void encodeAsEJBQL(PrintWriter pw, String rootId) {
+        try {
+            appendAsEJBQL(pw, rootId);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IOException 
appending to PrintWriter", e);
         }
     }
 
@@ -167,20 +193,17 @@ public class ASTList extends SimpleNode 
     }
 
     /**
-     * Sets an internal collection of values. Value argument
-     * can be an Object[], a Collection or an iterator.
+     * Sets an internal collection of values. Value argument can be an 
Object[],
+     * a Collection or an iterator.
      */
     protected void setValues(Object value) {
         if (value == null) {
             this.values = null;
-        }
-        else if (value instanceof Object[]) {
+        } else if (value instanceof Object[]) {
             this.values = (Object[]) value;
-        }
-        else if (value instanceof Collection) {
+        } else if (value instanceof Collection) {
             this.values = ((Collection) value).toArray();
-        }
-        else if (value instanceof Iterator) {
+        } else if (value instanceof Iterator) {
             List values = new ArrayList();
             Iterator it = (Iterator) value;
             while (it.hasNext()) {
@@ -188,11 +211,8 @@ public class ASTList extends SimpleNode 
             }
 
             this.values = values.toArray();
-        }
-        else {
-            throw new IllegalArgumentException(
-                "Invalid value class '"
-                    + value.getClass().getName()
+        } else {
+            throw new IllegalArgumentException("Invalid value class '" + 
value.getClass().getName()
                     + "', expected null, Object[], Collection, Iterator");
         }
     }

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTObjPath.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTObjPath.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTObjPath.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTObjPath.java
 Mon Mar 18 19:30:55 2013
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.exp.parser;
 
-import java.io.PrintWriter;
+import java.io.IOException;
 
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.DataObject;
@@ -34,7 +34,7 @@ public class ASTObjPath extends ASTPath 
     private static final Log logObj = LogFactory.getLog(ASTObjPath.class);
 
     public static final String OBJ_PREFIX = "obj:";
-    
+
     /**
      * Constructor used by expression parser. Do not invoke directly.
      */
@@ -53,10 +53,8 @@ public class ASTObjPath extends ASTPath 
 
     @Override
     protected Object evaluateNode(Object o) throws Exception {
-        return (o instanceof DataObject)
-                ? ((DataObject) o).readNestedProperty(path)
-                : (o instanceof Entity) ? evaluateEntityNode((Entity) o) : 
PropertyUtils
-                        .getProperty(o, path);
+        return (o instanceof DataObject) ? ((DataObject) 
o).readNestedProperty(path)
+                : (o instanceof Entity) ? evaluateEntityNode((Entity) o) : 
PropertyUtils.getProperty(o, path);
     }
 
     /**
@@ -69,28 +67,22 @@ public class ASTObjPath extends ASTPath 
         return copy;
     }
 
-    @Override
-    public void encodeAsString(PrintWriter pw) {
-        pw.print(path);
-    }
-
     /**
-     * @since 3.0
+     * @since 3.2
      */
     @Override
-    public void encodeAsEJBQL(PrintWriter pw, String rootId) {
-        pw.print(rootId);
-        pw.print('.');
-        pw.print(path);
+    public void appendAsEJBQL(Appendable out, String rootId) throws 
IOException {
+        out.append(rootId);
+        out.append('.');
+        out.append(path);
     }
-    
+
     /**
      * @since 3.2
      */
     @Override
-    public String toString() {
-        // shouldn't rely on super, see CAY-1803
-        return path;
+    public void appendAsString(Appendable out) throws IOException {
+        out.append(path);
     }
 
     @Override
@@ -103,15 +95,12 @@ public class ASTObjPath extends ASTPath 
             try {
                 if (source instanceof DataObject) {
                     ((DataObject) source).writeProperty(getPath(), value);
-                }
-                else {
+                } else {
                     PropertyUtils.setProperty(source, getPath(), value);
                 }
-            }   
-            catch (CayenneRuntimeException ex) {
-                logObj.warn("Failed to inject value " + value + 
-                        " on path " + getPath() + " to " + source, ex);
+            } catch (CayenneRuntimeException ex) {
+                logObj.warn("Failed to inject value " + value + " on path " + 
getPath() + " to " + source, ex);
             }
-       }
+        }
     }
 }

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTScalar.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTScalar.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTScalar.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/ASTScalar.java
 Mon Mar 18 19:30:55 2013
@@ -19,8 +19,10 @@
 
 package org.apache.cayenne.exp.parser;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.exp.Expression;
@@ -65,19 +67,49 @@ public class ASTScalar extends SimpleNod
         return copy;
     }
 
+    /**
+     * @deprecated since 3.2 use {@link #appendAsString(Appendable)}
+     */
     @Override
+    @Deprecated
     public void encodeAsString(PrintWriter pw) {
-        SimpleNode.encodeScalarAsString(pw, value, '\"');
+        try {
+            appendAsString(pw);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("UNexpected IOException 
appending to PrintWriter", e);
+        }
     }
 
     /**
+     * @since 3.2
+     */
+    @Override
+    public void appendAsString(Appendable out) throws IOException {
+        SimpleNode.appendScalarAsString(out, value, '\"');
+    }
+
+    /**
+     * @deprecated since 3.2 use {@link #appendAsEJBQL(Appendable, String)}.
      * @since 3.0
      */
+    @Deprecated
     @Override
     public void encodeAsEJBQL(PrintWriter pw, String rootId) {
+        try {
+            appendAsEJBQL(pw, rootId);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IOException 
appending to PrintWriter", e);
+        }
+    }
 
+    /**
+     * @since 3.2
+     */
+    @Override
+    public void appendAsEJBQL(Appendable out, String rootId) throws 
IOException {
         // TODO: see CAY-1111
-        // Persistent processing is a hack for a rather special case of a 
single column PK
+        // Persistent processing is a hack for a rather special case of a 
single
+        // column PK
         // object.. full implementation pending...
         Object scalar = value;
         if (scalar instanceof Persistent) {
@@ -89,7 +121,7 @@ public class ASTScalar extends SimpleNod
             }
         }
 
-        SimpleNode.encodeScalarAsString(pw, scalar, '\'');
+        SimpleNode.appendScalarAsString(out, scalar, '\'');
     }
 
     public void setValue(Object value) {
@@ -102,8 +134,7 @@ public class ASTScalar extends SimpleNod
 
     @Override
     protected String getExpressionOperator(int index) {
-        throw new UnsupportedOperationException("No operator for '"
-                + ExpressionParserTreeConstants.jjtNodeName[id]
+        throw new UnsupportedOperationException("No operator for '" + 
ExpressionParserTreeConstants.jjtNodeName[id]
                 + "'");
     }
 }

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/IgnoreCaseNode.java
 Mon Mar 18 19:30:55 2013
@@ -18,7 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.exp.parser;
 
-import java.io.PrintWriter;
+import java.io.IOException;
 
 import org.apache.cayenne.exp.ExpressionException;
 
@@ -33,20 +33,21 @@ abstract class IgnoreCaseNode extends Pa
     IgnoreCaseNode(int i, boolean ignoringCase, char escapeChar) {
         super(i, ignoringCase, escapeChar);
     }
-    
+
     @Override
-    protected void encodeChildrenAsEJBQL(PrintWriter pw, String rootId) {
-        //with like, first expression is always path, second is a literal, 
which must be uppercased
-        pw.print("upper(");
-        ((SimpleNode) children[0]).encodeAsEJBQL(pw, rootId);
-        pw.print(") ");
-        pw.print(getEJBQLExpressionOperator(0));
-        pw.print(" ");
-        
+    protected void appendChildrenAsEJBQL(Appendable out, String rootId) throws 
IOException {
+        // with like, first expression is always path, second is a literal,
+        // which must be uppercased
+        out.append("upper(");
+        ((SimpleNode) children[0]).appendAsEJBQL(out, rootId);
+        out.append(") ");
+        out.append(getEJBQLExpressionOperator(0));
+        out.append(" ");
+
         Object literal = ((ASTScalar) children[1]).getValue();
         if (!(literal instanceof String)) {
             throw new ExpressionException("Literal value should be a string");
         }
-        SimpleNode.encodeScalarAsString(pw, ((String) literal).toUpperCase(), 
'\'');
+        SimpleNode.appendScalarAsString(out, ((String) literal).toUpperCase(), 
'\'');
     }
 }

Modified: 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/SimpleNode.java
URL: 
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/SimpleNode.java?rev=1457927&r1=1457926&r2=1457927&view=diff
==============================================================================
--- 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/SimpleNode.java
 (original)
+++ 
cayenne/main/trunk/framework/cayenne-jdk1.5-unpublished/src/main/java/org/apache/cayenne/exp/parser/SimpleNode.java
 Mon Mar 18 19:30:55 2013
@@ -21,10 +21,12 @@
 
 package org.apache.cayenne.exp.parser;
 
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.Collections;
 import java.util.Map;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.ObjectId;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.exp.Expression;
@@ -32,11 +34,11 @@ import org.apache.cayenne.exp.Expression
 import org.apache.cayenne.util.Util;
 
 /**
- * Superclass of AST* expressions that implements Node interface defined by 
JavaCC
- * framework.
+ * Superclass of AST* expressions that implements Node interface defined by
+ * JavaCC framework.
  * <p>
- * Some parts of the parser are based on OGNL parser, copyright (c) 2002, Drew 
Davidson
- * and Luke Blanshard.
+ * Some parts of the parser are based on OGNL parser, copyright (c) 2002, Drew
+ * Davidson and Luke Blanshard.
  * </p>
  * 
  * @since 1.1
@@ -48,16 +50,14 @@ public abstract class SimpleNode extends
     protected int id;
 
     /**
-     * Utility method that encodes an object that is not an expression Node to 
String.
+     * Utility method that encodes an object that is not an expression Node to
+     * String.
      */
-    protected static void encodeScalarAsString(
-            PrintWriter pw,
-            Object scalar,
-            char quoteChar) {
+    protected static void appendScalarAsString(Appendable out, Object scalar, 
char quoteChar) throws IOException {
         boolean quote = scalar instanceof String;
 
         if (quote) {
-            pw.print(quoteChar);
+            out.append(quoteChar);
         }
 
         // encode only ObjectId for Persistent, ensure that the order of keys 
is
@@ -67,58 +67,56 @@ public abstract class SimpleNode extends
         if (scalar instanceof Persistent) {
             ObjectId id = ((Persistent) scalar).getObjectId();
             Object encode = (id != null) ? id : scalar;
-            encodeAsEscapedString(pw, String.valueOf(encode));
-        }
-        else if (scalar instanceof Enum<?>) {
+            appendAsEscapedString(out, String.valueOf(encode));
+        } else if (scalar instanceof Enum<?>) {
             Enum<?> e = (Enum<?>) scalar;
-            pw.print("enum:");
-            pw.print(e.getClass().getName() + "." + e.name());
-        }
-        else {
-            encodeAsEscapedString(pw, String.valueOf(scalar));
+            out.append("enum:");
+            out.append(e.getClass().getName() + "." + e.name());
+        } else {
+            appendAsEscapedString(out, String.valueOf(scalar));
         }
 
         if (quote) {
-            pw.print(quoteChar);
+            out.append(quoteChar);
         }
     }
 
     /**
-     * Utility method that prints a string to the provided PrintWriter, 
escaping special
-     * characters.
+     * Utility method that prints a string to the provided Appendable, escaping
+     * special characters.
      */
-    protected static void encodeAsEscapedString(PrintWriter pw, String source) 
{
+    protected static void appendAsEscapedString(Appendable out, String source) 
throws IOException {
         int len = source.length();
         for (int i = 0; i < len; i++) {
             char c = source.charAt(i);
 
             switch (c) {
-                case '\n':
-                    pw.print("\\n");
-                    continue;
-                case '\r':
-                    pw.print("\\r");
-                    continue;
-                case '\t':
-                    pw.print("\\t");
-                    continue;
-                case '\b':
-                    pw.print("\\b");
-                    continue;
-                case '\f':
-                    pw.print("\\f");
-                    continue;
-                case '\\':
-                    pw.print("\\\\");
-                    continue;
-                case '\'':
-                    pw.print("\\'");
-                    continue;
-                case '\"':
-                    pw.print("\\\"");
-                    continue;
-                default:
-                    pw.print(c);
+            case '\n':
+                out.append("\\n");
+                continue;
+            case '\r':
+                out.append("\\r");
+                continue;
+            case '\t':
+                out.append("\\t");
+                continue;
+            case '\b':
+                out.append("\\b");
+                continue;
+            case '\f':
+                out.append("\\f");
+                continue;
+            case '\\':
+                out.append("\\\\");
+                continue;
+            case '\'':
+                out.append("\\'");
+                continue;
+            case '\"':
+                out.append("\\\"");
+                continue;
+            default:
+                out.append(c);
             }
         }
     }
@@ -140,8 +138,8 @@ public abstract class SimpleNode extends
     protected abstract String getExpressionOperator(int index);
 
     /**
-     * Returns operator for ebjql statements, which can differ for Cayenne 
expression
-     * operator
+     * Returns operator for ebjql statements, which can differ for Cayenne
+     * expression operator
      */
     protected String getEJBQLExpressionOperator(int index) {
         return getExpressionOperator(index);
@@ -161,8 +159,8 @@ public abstract class SimpleNode extends
     }
 
     /**
-     * Flattens the tree under this node by eliminating any children that are 
of the same
-     * class as this node and copying their children to this node.
+     * Flattens the tree under this node by eliminating any children that are 
of
+     * the same class as this node and copying their children to this node.
      */
     @Override
     protected void flattenTree() {
@@ -173,8 +171,7 @@ public abstract class SimpleNode extends
             if (child.getClass() == getClass()) {
                 shouldFlatten = true;
                 newSize += child.jjtGetNumChildren();
-            }
-            else {
+            } else {
                 newSize++;
             }
         }
@@ -188,8 +185,7 @@ public abstract class SimpleNode extends
                     for (int k = 0; k < c.jjtGetNumChildren(); ++k) {
                         newChildren[j++] = c.jjtGetChild(k);
                     }
-                }
-                else {
+                } else {
                     newChildren[j++] = c;
                 }
             }
@@ -202,31 +198,47 @@ public abstract class SimpleNode extends
         }
     }
 
+    /**
+     * @since 3.2
+     */
     @Override
-    public void encodeAsString(PrintWriter pw) {
+    public void appendAsString(Appendable out) throws IOException {
+
         if (parent != null) {
-            pw.print("(");
+            out.append("(");
         }
 
         if ((children != null) && (children.length > 0)) {
             for (int i = 0; i < children.length; ++i) {
                 if (i > 0) {
-                    pw.print(' ');
-                    pw.print(getExpressionOperator(i));
-                    pw.print(' ');
+                    out.append(' ');
+                    out.append(getExpressionOperator(i));
+                    out.append(' ');
                 }
 
                 if (children[i] == null) {
-                    pw.print("null");
-                }
-                else {
-                    ((SimpleNode) children[i]).encodeAsString(pw);
+                    out.append("null");
+                } else {
+                    ((SimpleNode) children[i]).appendAsString(out);
                 }
             }
         }
 
         if (parent != null) {
-            pw.print(')');
+            out.append(')');
+        }
+    }
+
+    /**
+     * @deprecated since 3.2 use {@link #appendAsString(Appendable)}.
+     */
+    @Override
+    @Deprecated
+    public void encodeAsString(PrintWriter pw) {
+        try {
+            appendAsString(pw);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IO exception 
appending to PrintWriter", e);
         }
     }
 
@@ -234,17 +246,20 @@ public abstract class SimpleNode extends
     public Object getOperand(int index) {
         Node child = jjtGetChild(index);
 
-        // unwrap ASTScalar nodes - this is likely a temporary thing to keep 
it compatible
-        // with QualifierTranslator. In the future we might want to keep 
scalar nodes
+        // unwrap ASTScalar nodes - this is likely a temporary thing to keep it
+        // compatible
+        // with QualifierTranslator. In the future we might want to keep scalar
+        // nodes
         // for the purpose of expression evaluation.
         return unwrapChild(child);
     }
 
     protected Node wrapChild(Object child) {
-        // when child is null, there's no way of telling whether this is a 
scalar or
-        // not... fuzzy... maybe we should stop using this method - it is too 
generic
-        return (child instanceof Node || child == null) ? (Node) child : new 
ASTScalar(
-                child);
+        // when child is null, there's no way of telling whether this is a
+        // scalar or
+        // not... fuzzy... maybe we should stop using this method - it is too
+        // generic
+        return (child instanceof Node || child == null) ? (Node) child : new 
ASTScalar(child);
     }
 
     protected Object unwrapChild(Node child) {
@@ -258,9 +273,7 @@ public abstract class SimpleNode extends
 
     @Override
     public void setOperand(int index, Object value) {
-        Node node = (value == null || value instanceof Node)
-                ? (Node) value
-                : new ASTScalar(value);
+        Node node = (value == null || value instanceof Node) ? (Node) value : 
new ASTScalar(value);
         jjtAddChild(node, index);
 
         // set the parent, as jjtAddChild doesn't do it...
@@ -288,8 +301,7 @@ public abstract class SimpleNode extends
     public void jjtAddChild(Node n, int i) {
         if (children == null) {
             children = new Node[i + 1];
-        }
-        else if (i >= children.length) {
+        } else if (i >= children.length) {
             Node c[] = new Node[i + 1];
             System.arraycopy(children, 0, c, 0, children.length);
             children = c;
@@ -318,7 +330,8 @@ public abstract class SimpleNode extends
     protected void connectChildren() {
         if (children != null) {
             for (Node child : children) {
-                // although nulls are expected to be wrapped in scalar, still 
doing a
+                // although nulls are expected to be wrapped in scalar, still
+                // doing a
                 // check here to make it more robust
                 if (child != null) {
                     child.jjtSetParent(this);
@@ -342,50 +355,57 @@ public abstract class SimpleNode extends
         // wrap in try/catch to provide unified exception processing
         try {
             return evaluateNode(o);
-        }
-        catch (Throwable th) {
+        } catch (Throwable th) {
             String string = this.toString();
-            throw new ExpressionException(
-                    "Error evaluating expression '" + string + "'",
-                    string,
+            throw new ExpressionException("Error evaluating expression '" + 
string + "'", string,
                     Util.unwindException(th));
         }
     }
 
     /**
      * @since 3.0
+     * @deprecated since 3.2 use {@link #appendAsEJBQL(Appendable, String)}.
      */
     @Override
+    @Deprecated
     public void encodeAsEJBQL(PrintWriter pw, String rootId) {
+        try {
+            appendAsEJBQL(pw, rootId);
+        } catch (IOException e) {
+            throw new CayenneRuntimeException("Unexpected IO exception 
appending to PrintWriter", e);
+        }
+    }
+
+    @Override
+    public void appendAsEJBQL(Appendable out, String rootId) throws 
IOException {
         if (parent != null) {
-            pw.print("(");
+            out.append("(");
         }
 
         if ((children != null) && (children.length > 0)) {
-            encodeChildrenAsEJBQL(pw, rootId);
+            appendChildrenAsEJBQL(out, rootId);
         }
 
         if (parent != null) {
-            pw.print(')');
+            out.append(')');
         }
     }
 
     /**
      * Encodes child of this node with specified index to EJBQL
      */
-    protected void encodeChildrenAsEJBQL(PrintWriter pw, String rootId) {
+    protected void appendChildrenAsEJBQL(Appendable out, String rootId) throws 
IOException {
         for (int i = 0; i < children.length; ++i) {
             if (i > 0) {
-                pw.print(' ');
-                pw.print(getEJBQLExpressionOperator(i));
-                pw.print(' ');
+                out.append(' ');
+                out.append(getEJBQLExpressionOperator(i));
+                out.append(' ');
             }
 
             if (children[i] == null) {
-                pw.print("null");
-            }
-            else {
-                ((SimpleNode) children[i]).encodeAsEJBQL(pw, rootId);
+                out.append("null");
+            } else {
+                ((SimpleNode) children[i]).appendAsEJBQL(out, rootId);
             }
         }
     }


Reply via email to