openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r802984 - in /openjpa/trunk: openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-kernel/src/test/java/org/apache/openjpa/util/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/ openjpa-persi...
Date Tue, 11 Aug 2009 03:02:46 GMT
Author: ppoddar
Date: Tue Aug 11 03:02:45 2009
New Revision: 802984

URL: http://svn.apache.org/viewvc?rev=802984&view=rev
Log:
OPENJPA-1225: 
Refactor FillStrategy out of ResultShape enum to a separate interface. 
Introduce CompoundSelections.MultiSelect
Use ObjectFactory for Tuple to save memory
Tune CriteriaExpressionBuilder to new result packing
Isolate ResultPacker (JPQL) from ResultShape (Criteria) completely 
Implement getSelection() for JPA 2.0

Added:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java   (with props)
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java   (with props)
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java   (with props)
Modified:
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
    openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultShape.java
    openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/util/TestResultShape.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/Foo_.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java
    openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleElementImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompoundSelections.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java
    openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
    openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
    openjpa/trunk/openjpa-persistence/src/test/java/org/apache/openjpa/persistence/TestTupleImpl.java

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java?rev=802984&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java Tue Aug 11 03:02:45 2009
@@ -0,0 +1,206 @@
+/*
+ * 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.openjpa.kernel;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.openjpa.enhance.Reflection;
+
+
+/**
+ * A strategy to fill data into a {@link ResultShape}.
+ * <BR>
+ * Available strategy implementations can fill by invoking constructor, setting array elements, direct assignment,
+ * invoking put(key,value)-style methods or a constructing by a factory. 
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
+public interface FillStrategy<T> {
+    T fill(Object[] data, Class<?>[] types, String[] aliases);
+    
+    
+    /**
+     * Fills an array of given type. 
+     *
+     * @param <T> must be an array type.
+     */
+    public static class Array<T> implements FillStrategy<T> {
+        private final Class<?> cls;
+        public Array(Class<T> arrayCls) {
+            if (!arrayCls.isArray())
+                throw new IllegalArgumentException(arrayCls + " is not an array");
+            this.cls = arrayCls.getComponentType();
+        }
+        
+        public T fill(Object[] values, Class<?>[] types, String[] aliases) {
+            Object array = java.lang.reflect.Array.newInstance(cls, values.length);
+            System.arraycopy(values, 0, array, 0, values.length);
+            return (T)array;
+        }
+    }
+    
+    /**
+     * Construct and populate an instance by invoking the put method 
+     * with each alias as key and element of the given array of values.
+     * 
+     * The instance is a created by the no-argument constructor of the declaring class of the given method.
+     */
+    public static class Map<T> implements FillStrategy<T> {
+        private final Method putMethod;
+        
+        public Map(Method put) {
+            putMethod = put;
+        }
+        
+        public T fill(Object[] values, Class<?>[] types, String[] aliases) {
+            try {
+                Object map = putMethod.getDeclaringClass().newInstance();
+                for (int i = 0; i < values.length; i++)
+                    putMethod.invoke(map, aliases[i], values[i]);
+                return (T)map;
+            } catch (InvocationTargetException t) {
+                throw new RuntimeException(t.getTargetException());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+    }
+    
+    /**
+     * Construct and populate an instance by the given constructor and arguments.
+     */
+    public static class NewInstance<T> implements FillStrategy<T> {
+        private Constructor<? extends T> cons;
+        private Class<T> cls;
+        public NewInstance(Constructor<? extends T> cons) {
+            this.cons = cons;
+        }
+        
+        public NewInstance(Class<T> cls) {
+            this.cls = cls;
+        }
+        
+        
+        /**
+         * Finds a constructor of the given class with given argument types.
+         */
+        <X> Constructor<X> findConstructor(Class<X> cls, Class<?>[] types) {
+            try {
+                return cls.getConstructor(types);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+        public T fill(Object[] values, Class<?>[] types, String[] aliases) {
+            if (cons == null) {
+                cons = findConstructor(cls, types);
+            }
+            try {
+                for (int i = 0; i < values.length; i++) {
+                    values[i] = Filters.convert(values[i], types[i]);
+                }
+                return cons.newInstance(values);
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+        
+    }
+    
+    /**
+     * Create and populate a bean by invoking setter methods identified by alias name with each array
+     * element value as argument.
+     */
+    public static class Bean<T> implements FillStrategy<T> {
+        private final Class<T> cls;
+        private Method[] setters;
+        
+        public Bean(Class<T> cls) {
+            this.cls = cls;
+        }
+    
+        public T fill(Object[] args, Class<?>[] types, String[] aliases) {
+            try {
+                if (setters == null) {
+                    setters = new Method[args.length];
+                }
+                T bean = cls.newInstance();
+                for (int i = 0; i < args.length; i++) {
+                    if (setters[i] == null) {
+                        setters[i] = Reflection.findSetter(cls, aliases[i], true);
+                    }
+                    setters[i].invoke(bean, args[i]);
+                }
+                return bean;
+            } catch (InvocationTargetException t) {
+                throw new RuntimeException(t.getTargetException());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+    
+    
+    /**
+     * Populate an instance by simply assigning the 0-th element of the input values.  
+     */
+    public static class Assign<T> implements FillStrategy<T> {
+        public T fill(Object[] args, Class<?>[] types, String[] aliases) {
+            return (T)args[0];
+        }
+    }
+    
+    /**
+     * Populate an instance created by given factory using a given put(key,value) method.
+     * If the first argument of the given put method is integer then fill the values
+     * by index else fill the values with alias key.  
+     */
+    public static class Factory<T> implements FillStrategy<T> {
+        final ObjectFactory<T> factory;
+        final Method putMethod;
+        final boolean isArray;
+        
+        public Factory(ObjectFactory<T> factory, Method putMethod) {
+            this.factory = factory;
+            this.putMethod = putMethod;
+            Class<?> keyType = putMethod.getParameterTypes()[0];
+            this.isArray = keyType == int.class || keyType == Integer.class;
+        }
+        
+        public T fill(Object[] values, Class<?>[] types, String[] aliases) {
+            T result = factory.newInstance();
+            try {
+                for (int i = 0; i < values.length; i++)
+                    putMethod.invoke(result, isArray ? i : aliases[i], values[i]);
+                return result;
+            } catch (InvocationTargetException t) {
+                throw new RuntimeException(t.getTargetException());
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FillStrategy.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java?rev=802984&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java Tue Aug 11 03:02:45 2009
@@ -0,0 +1,33 @@
+/*
+ * 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.openjpa.kernel;
+
+/**
+ * An interface to create objects that are used by result processing.
+ * @see FillStrategy.Factory
+ * 
+ * @author Pinaki Poddar
+ * @since 2.0.0
+ * 
+ * @param <T> the type created by this factory.
+ * 
+ */
+public interface ObjectFactory<T> {
+    public T newInstance();
+}

Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java Tue Aug 11 03:02:45 2009
@@ -1263,17 +1263,21 @@
             return null;
 
         String[] aliases = ex.getProjectionAliases(q);
-        if (aliases.length == 0) {
-            // result class but no result; means candidate is being set
-            // into some result class
-            _packer = new ResultPacker(_class, getAlias(), resultClass);
-        } else if (resultClass != null) { // projection
-            ResultShape shape = ex.getResultShape(q);
-            Class[] types = ex.getProjectionTypes(q);
-            if (shape == null) {
-                _packer = new ResultPacker(types, aliases, resultClass);
+        ResultShape<?> shape = ex.getResultShape(q);
+        if (shape != null) { // using JPA2.0 style result shape for packing
+            if (aliases.length == 0) {
+                _packer = new ResultShapePacker(new Class[]{_class}, new String[]{""}, resultClass, shape);
             } else {
-                _packer = new ResultShapePacker(types, aliases, resultClass, shape);
+                _packer = new ResultShapePacker(ex.getProjectionTypes(q), aliases, resultClass, shape);
+            }
+        } else {
+            if (aliases.length == 0) {
+                // result class but no result; means candidate is being set
+                // into some result class
+                _packer = new ResultPacker(_class, getAlias(), resultClass);
+            } else if (resultClass != null) { // projection
+                Class[] types = ex.getProjectionTypes(q);
+                _packer = new ResultPacker(types, aliases, resultClass);
             }
         }
         return _packer;

Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultShape.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultShape.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultShape.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ResultShape.java Tue Aug 11 03:02:45 2009
@@ -1,19 +1,31 @@
+/*
+ * 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.openjpa.kernel;
 
 import java.io.Serializable;
 import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import org.apache.openjpa.enhance.Reflection;
-import org.apache.openjpa.kernel.Filters;
-
 /**
  * Describes the shape of a query result.
  * <br>
@@ -50,27 +62,14 @@
  */
 @SuppressWarnings("serial")
 public class ResultShape<T> implements Serializable {
-    // Determines how to populate an instance from the input array values and aliases
-    public static enum FillStrategy {
-        ARRAY,       // copy input array elements to this shape's array element values
-        ASSIGN,      // assign the single input array element to this shape's value 
-        BEAN,        // invoke bean-style setter methods of alias names with array element values as arguments
-        CONSTRUCTOR, // invoke constructor with array element values as arguments
-        MAP          // invoke put(Object, Object) method with alias as key and array elements as values 
-    }
-    
     private final Class<T> cls;        // the type of value this shape represents or populates
     private final boolean isPrimitive; // flags this shape as primitive
     private boolean isNesting;         // flags this shape as nesting
     private String alias;
     
-    private final FillStrategy strategy;   // the strategy to populate this shape
+    private final FillStrategy<T> strategy;   // the strategy to populate this shape
     private final List<ResultShape<?>> children; // children of this shape. null for primitives
     private Set<ResultShape<?>> parents;   // the shapes that have nested this shape
-    
-    private Method putMethod;            // Population method for MAP FillStrategy
-    private Constructor<? extends T> constructor;  // Constructor for CONSTRUCTOR FillStrategy
-    private Method[] setters;            // Setter methods for BEAN FillStrategy
 
     /**
      * Construct a non-primitive shape with ASSIGN or ARRAY fill strategy. 
@@ -84,7 +83,7 @@
      * If the shape is declared as primitive then the given class can not be an array.
      */
     public ResultShape(Class<T> cls, boolean primitive) {
-        this(cls, cls.isArray() ? FillStrategy.ARRAY : FillStrategy.ASSIGN, primitive);
+        this(cls, cls.isArray() ? new FillStrategy.Array<T>(cls) : new FillStrategy.Assign<T>(), primitive);
         if (cls.isArray() && primitive)
             throw new IllegalArgumentException(cls.getSimpleName() + " can not be primitive shape");
     }
@@ -93,7 +92,7 @@
      * 
      * Construct a non-primitive shape with the given fill strategy. 
      */
-    public ResultShape(Class<T> cls, FillStrategy strategy) {
+    public ResultShape(Class<T> cls, FillStrategy<T> strategy) {
         this(cls, strategy, false);
     }
     
@@ -101,7 +100,7 @@
      * Construct a shape with the given fill strategy. 
      * 
      */
-    public ResultShape(Class<T> cls, FillStrategy strategy, boolean primitive) {
+    public ResultShape(Class<T> cls, FillStrategy<T> strategy, boolean primitive) {
         if (cls == null) throw new NullPointerException();
         this.cls = cls;
         this.strategy = strategy;
@@ -109,30 +108,29 @@
         children = isPrimitive ? null : new ArrayList<ResultShape<?>>();
     }
     
-    /**
-     * Construct a shape with the MAP fill strategy to invoke the given method. 
-     * 
-     */
-    public ResultShape(Class<T> cls, Method putMethod) {
-        if (cls == null) throw new NullPointerException();
-        this.cls = cls;
-        this.strategy = FillStrategy.MAP;
-        isPrimitive = true;
-        children = new ArrayList<ResultShape<?>>();
-    }
-
-    /**
-     * Construct a shape with the CONSTRUCTOR fill strategy to invoke the given constructor. 
-     * 
-     */
-    public ResultShape(Class<T> cls, Constructor<? extends T> cons) {
-        if (cls == null) throw new NullPointerException();
-        this.cls = cls;
-        this.strategy = FillStrategy.CONSTRUCTOR;
-        this.constructor = cons;
-        isPrimitive = false;
-        children = new ArrayList<ResultShape<?>>();
-    }
+//    /**
+//     * Construct a shape with the MAP fill strategy to invoke the given method. 
+//     * 
+//     */
+//    public ResultShape(Class<T> cls, Method putMethod) {
+//        if (cls == null) throw new NullPointerException();
+//        this.cls = cls;
+//        this.strategy = new FillStrategy.Map<T>(putMethod);
+//        isPrimitive = true;
+//        children = new ArrayList<ResultShape<?>>();
+//    }
+//
+//    /**
+//     * Construct a shape with the CONSTRUCTOR fill strategy to invoke the given constructor. 
+//     * 
+//     */
+//    public ResultShape(Class<T> cls, Constructor<? extends T> cons) {
+//        if (cls == null) throw new NullPointerException();
+//        this.cls = cls;
+//        this.strategy = new FillStrategy.NewInstance<T>(cons);
+//        isPrimitive = false;
+//        children = new ArrayList<ResultShape<?>>();
+//    }
     
     /**
      * Gets the type of instance populated by this shape.
@@ -141,7 +139,7 @@
         return cls;
     }
     
-    public FillStrategy getStrategy() {
+    public FillStrategy<T> getStrategy() {
         return strategy;
     }
     
@@ -341,7 +339,6 @@
         if (values.length < argLength()) // input can be longer than required
             throw new IndexOutOfBoundsException(values.length + " values are less than " + 
                     argLength() + " argumenets required to pack " + this); 
-        Object result = null;
         Object[] args = new Object[length()];
         Class<?>[] argTypes = new Class[length()];
         String[] argAliases = new String[length()];
@@ -362,27 +359,7 @@
                 i++;
             }
         }
-        initializeStrategyElements(cls, args, argTypes, aliases);
-        switch (strategy) {
-        case ARRAY:
-            result = newArray(cls.getComponentType(), args);
-            break;
-        case ASSIGN:
-            result = args[0];
-            break;
-        case CONSTRUCTOR:
-            result = newInstance(constructor, args, aliases);
-            break;
-        case MAP:
-            result = newMap(putMethod, args, aliases);
-            break;
-        case BEAN:
-            result = newBean(setters, args, aliases);
-            break;
-        default:
-            result = values;
-        }
-        return (T)result;
+        return (T)strategy.fill(args, argTypes, argAliases);
     }
 
     /**
@@ -393,114 +370,6 @@
         System.arraycopy(values, start, result, 0, finish-start);
         return result;
     }
-    
-    <X> X[] newArray(Class<X> cls, Object[] values) {
-        X[] result = (X[])Array.newInstance(cls, values.length);
-        System.arraycopy(values, 0, result, 0, values.length);
-        return result;
-    }
-    
-    /**
-     * Construct and populate an instance by the given constructor and arguments.
-     */
-    Object newInstance(Constructor<?> cons, Object[] args, String[] aliases) {
-        try {
-            Class[] types = cons.getParameterTypes();
-            for (int i = 0; i < args.length; i++) {
-                args[i] = Filters.convert(args[i], types[i]);
-            }
-            return cons.newInstance(args);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
-    /**
-     * Construct and populate an instance by invoking the put method 
-     * with each alias as key and element of the given args[] as value.
-     */
-    Object newMap(Method put, Object[] args, String[] aliases) {
-        try {
-            Object map = put.getDeclaringClass().newInstance();
-            for (int i = 0; i < args.length; i++)
-                putMethod.invoke(map, aliases[i], args[i]);
-            return map;
-        } catch (InvocationTargetException t) {
-            throw new RuntimeException(t.getTargetException());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
-    /**
-     * Create and populate a bean with the given setter methods with each array
-     * element value as argument.
-     */
-    Object newBean(Method[] setters, Object[] args, String[] aliases) {
-        try {
-            Object bean = cls.newInstance();
-            for (int i = 0; i < args.length; i++)
-                setters[i].invoke(bean, args[i]);
-            return bean;
-        } catch (InvocationTargetException t) {
-            throw new RuntimeException(t.getTargetException());
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
-    /**
-     * Initializes the mechanism to populate. Population mechanism can be a constructor,
-     * a put method for Map or bean-style setter methods.
-     */
-    void initializeStrategyElements(Class<T> cls, Object[] args, Class<?>[] types, String[] aliases) {
-        switch (strategy) {
-        case MAP:
-            if (putMethod == null)
-                putMethod = findMapPopulationMethod();
-            break;
-        case CONSTRUCTOR:
-            if (constructor == null)
-                constructor = findConstructor(cls, args, types);
-            break;
-        case BEAN:
-            if (setters == null) {
-                setters = new Method[args.length];
-                for (int i = 0; i < args.length; i++) {
-                    setters[i] = Reflection.findSetter(cls, aliases[i], true);
-                }
-            }
-            break;  
-        default:
-        }
-    }
-    
-    /**
-     * Find a method named <code>put(Object, Object)</code> or <code>put(String, Object)</code>.
-     */
-    Method findMapPopulationMethod() {
-        try {
-            return cls.getMethod("put", Object.class, Object.class);
-        } catch (Exception e1) {
-            try {
-                return cls.getMethod("put", String.class, Object.class);
-            } catch (Exception e2) {
-                throw new RuntimeException(e2);
-            }
-        }
-    }
-    
-    /**
-     * Finds a constructor of the given class with given argument types.
-     */
-    <X> Constructor<X> findConstructor(Class<X> cls, Object[] args, Class<?>[] types) {
-        try {
-            return cls.getConstructor(types);
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
     /**
      * Gets a human-readable representation of this shape.
      * 

Modified: openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/util/TestResultShape.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/util/TestResultShape.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/util/TestResultShape.java (original)
+++ openjpa/trunk/openjpa-kernel/src/test/java/org/apache/openjpa/util/TestResultShape.java Tue Aug 11 03:02:45 2009
@@ -1,3 +1,21 @@
+/*
+ * 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.openjpa.util;
 
 import java.lang.reflect.Constructor;
@@ -7,17 +25,17 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.openjpa.kernel.FillStrategy;
 import org.apache.openjpa.kernel.ResultShape;
 
 import junit.framework.TestCase;
-import static org.apache.openjpa.kernel.ResultShape.FillStrategy.*;
 
 public class TestResultShape extends TestCase {
 
     public void testPrimitiveShapeIsImmutable() {
         ResultShape<Object> shape = new ResultShape<Object>(Object.class, true);
         assertCategory(shape, true, false, false);
-        assertEquals(ASSIGN, shape.getStrategy());
+        assertEquals(FillStrategy.Assign.class, shape.getStrategy().getClass());
         
         try {
             shape.add(int.class);
@@ -25,7 +43,7 @@
         } catch (UnsupportedOperationException e) {
         }
         try {
-            shape.nest(Object[].class, ARRAY, int.class, double.class);
+            shape.nest(Object[].class, new FillStrategy.Array(Object[].class), int.class, double.class);
             fail(shape + " should not allow nesting other shapes");
         } catch (UnsupportedOperationException e) {
         }
@@ -34,7 +52,7 @@
     public void testArrayIsMutable() {
         ResultShape<Object[]> shape = new ResultShape<Object[]>(Object[].class);
         assertCategory(shape, false, true, false);
-        assertEquals(ARRAY, shape.getStrategy());
+        assertEquals(FillStrategy.Array.class, shape.getStrategy().getClass());
         
         shape.add(int.class, double.class); // will add primitive shapes
         assertCategory(shape, false, true, false);
@@ -51,29 +69,31 @@
     }
 
     public void testMethodImpliesMapStrategy() {
-        ResultShape<Map> mapShape = new ResultShape<Map>(Map.class, 
-                method(Map.class, "put", Object.class, Object.class));
+        FillStrategy<Map> strategy = new FillStrategy.Map<Map>(method(Map.class, "put", Object.class, Object.class));
+        ResultShape<Map> mapShape = new ResultShape<Map>(Map.class, strategy, true);
         assertCategory(mapShape, true, false, false);
-        assertEquals(MAP, mapShape.getStrategy());
+        assertEquals(FillStrategy.Map.class, mapShape.getStrategy().getClass());
     }
 
     public void testShapeWithConstrcutorStrategy() {
-        ResultShape<List> listShape = new ResultShape<List>(List.class, constructor(ArrayList.class, int.class));
+        FillStrategy<List> strategy = new FillStrategy.NewInstance<List>(constructor(ArrayList.class, int.class));
+        ResultShape<List> listShape = new ResultShape<List>(List.class, strategy);
         assertCategory(listShape, false, true, false);
-        assertEquals(CONSTRUCTOR, listShape.getStrategy());
+        assertEquals(FillStrategy.NewInstance.class, listShape.getStrategy().getClass());
     }
 
     public void testGetCompositeTypes() {
-        ResultShape<Object[]> root = new ResultShape<Object[]>(Object[].class);
-        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Object[]> root  = new ResultShape<Object[]>(Object[].class);
+        FillStrategy<Bar> strategy1 = new FillStrategy.NewInstance<Bar>(Bar.class);
+        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, strategy1, false);
         bar1.add(int.class);
-        ResultShape<Foo> fooBarConstructor = new ResultShape<Foo>(Foo.class, 
-                constructor(Foo.class, short.class, Bar.class));
+        FillStrategy<Foo> strategy2 = new FillStrategy.NewInstance<Foo>(constructor(Foo.class, short.class, Bar.class));
+        ResultShape<Foo> fooBarConstructor = new ResultShape<Foo>(Foo.class, strategy2);
         fooBarConstructor.add(short.class);
         fooBarConstructor.nest(bar1);
         root.add(Foo.class, Object.class);
         root.nest(fooBarConstructor);
-        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
         root.nest(bar2);
         assertEquals("Object[]{Foo, Object, Foo{short, Bar{int}}, Bar}", root.toString());
         assertEquals(Arrays.asList(Foo.class, Object.class, short.class, int.class, Bar.class), 
@@ -85,15 +105,15 @@
 
     public void testRecursiveNestingIsNotAllowed() {
         ResultShape<Object[]> root = new ResultShape<Object[]>(Object[].class);
-        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
         bar1.add(int.class);
         ResultShape<Foo> fooBarConstructor = new ResultShape<Foo>(Foo.class, 
-                constructor(Foo.class, short.class, Bar.class));
+                new FillStrategy.NewInstance(constructor(Foo.class, short.class, Bar.class)));
         fooBarConstructor.add(short.class);
         fooBarConstructor.nest(bar1);
         root.add(Foo.class, Object.class);
         root.nest(fooBarConstructor);
-        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
         root.nest(bar2);
         
         try {
@@ -107,8 +127,8 @@
 
     public void testFill() {
         //Fill this shape: Foo{short, Bar{String, Double}};
-        ResultShape<Foo> foo = new ResultShape<Foo>(Foo.class, CONSTRUCTOR, false);
-        ResultShape<Bar> bar = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Foo> foo = new ResultShape<Foo>(Foo.class, new FillStrategy.NewInstance(Foo.class), false);
+        ResultShape<Bar> bar = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance(Bar.class), false);
         bar.add(String.class, Double.class);
         foo.add(short.class);
         foo.nest(bar);
@@ -126,15 +146,15 @@
     public void testFill2() {
         //Fill this shape: Object[]{Foo, Object, Foo{short, Bar{String, Double}}, Bar{double}};
         ResultShape<Object[]> root = new ResultShape<Object[]>(Object[].class);
-        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Bar> bar1 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance<Bar>(Bar.class));
         bar1.add(String.class, Double.class);
-        ResultShape<Foo> fooBarConstructor = new ResultShape<Foo>(Foo.class, CONSTRUCTOR, false);
-        fooBarConstructor.add(short.class);
-        fooBarConstructor.nest(bar1);
-        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, CONSTRUCTOR, false);
+        ResultShape<Foo> fooBarConstr = new ResultShape<Foo>(Foo.class, new FillStrategy.NewInstance<Foo>(Foo.class));
+        fooBarConstr.add(short.class);
+        fooBarConstr.nest(bar1);
+        ResultShape<Bar> bar2 = new ResultShape<Bar>(Bar.class, new FillStrategy.NewInstance<Bar>(Bar.class));
         bar2.add(double.class);
         root.add(Foo.class, Object.class);
-        root.nest(fooBarConstructor);
+        root.nest(fooBarConstr);
         root.nest(bar2);
         assertEquals("Object[]{Foo, Object, Foo{short, Bar{String, Double}}, Bar{double}}", root.toString());
         

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/Foo_.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/Foo_.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/Foo_.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/Foo_.java Tue Aug 11 03:02:45 2009
@@ -32,6 +32,7 @@
     public static volatile SingularAttribute<Foo, Long> fid;
     public static volatile SingularAttribute<Foo, String> fstring;
     public static volatile SingularAttribute<Foo, Integer> fint;
+    public static volatile SingularAttribute<Foo, Long> flong;
     public static volatile SingularAttribute<Foo, Bar> bar;
 
 }

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestMultiselect.java Tue Aug 11 03:02:45 2009
@@ -30,7 +30,6 @@
 import org.apache.openjpa.persistence.criteria.CriteriaTest;
 import org.apache.openjpa.persistence.criteria.Person;
 import org.apache.openjpa.persistence.criteria.Person_;
-import org.apache.openjpa.persistence.test.AllowFailure;
 
 
 /**
@@ -183,13 +182,12 @@
         assertResult(q, String[].class);
     }
     
-    @AllowFailure(message="TupleArray needs special processing at multiselect")
     public void testTupleArray() {
         CriteriaQuery<Tuple[]> q = cb.createQuery(Tuple[].class);
         Root<Person> p = q.from(Person.class); 
-        q.multiselect(p.get(Person_.name), p.get(Person_.name));
+        q.multiselect(p.get(Person_.name), p.get(Person_.id), p.get(Person_.name));
         
-        assertResult(q, Tuple[].class);
+        assertResult(q, Tuple[].class, String.class, Integer.class, String.class);
     }
 // =================================================================    
     /**
@@ -265,8 +263,6 @@
         assertResult(q, Object[].class, String.class, Integer.class);
     }
     
-    @AllowFailure(message="Mixing constructor with other projections get CriteriaExpressionBuilder.getProjections() " +
-            "all messed up")
     public void testSingleObjectMultipleProjectionsAndConstructor() {
         CriteriaQuery<Object> q = cb.createQuery(Object.class);
         Root<Person> p = q.from(Person.class);
@@ -278,8 +274,10 @@
     /**
      * An element of the list passed to the multiselect method 
      * must not be a tuple- or array-valued compound selection item. 
+     * 
      */
-    public void testTupleCanNotBeNested() {
+    // This test is retired because we are now supporting arbitrary nesting 
+    public void xtestTupleCanNotBeNested() {
         CriteriaQuery<Tuple> q = cb.createTupleQuery();
         Root<Person> p = q.from(Person.class);
         
@@ -314,6 +312,73 @@
         }
     }
     
+    public void testSelectSingleTermWithMultiselectObjectArray() {
+        CriteriaQuery<Object[]> q = cb.createQuery(Object[].class);
+        Root<Foo> f = q.from(Foo.class);
+        q.multiselect(f);
+        
+        assertResult(q, Object[].class, Foo.class);
+    }
+    
+    public void testSelectSingleTermWithMultiselectObject() {
+        CriteriaQuery<Object> q = cb.createQuery(Object.class);
+        Root<Foo> f = q.from(Foo.class);
+        q.multiselect(f);
+        
+        assertResult(q, Foo.class);
+    }
+    
+    public void testSelectSingleTermWithMultiselectTuple() {
+        CriteriaQuery<Tuple> q = cb.createQuery(Tuple.class);
+        Root<Foo> f = q.from(Foo.class);
+        q.multiselect(f);
+        
+        assertResult(q, Tuple.class, Foo.class);
+    }
+    
+    public void testSelectSingleTermWithMultiselectTupleArray() {
+        CriteriaQuery<Tuple[]> q = cb.createQuery(Tuple[].class);
+        Root<Foo> f = q.from(Foo.class);
+        q.multiselect(f);
+        
+        assertResult(q, Tuple[].class, Foo.class);
+    }
+    
+    public void testSanity() {
+        CriteriaQuery<Foo> q = cb.createQuery(Foo.class);
+        Root<Foo> f = q.from(Foo.class);
+        
+        assertResult(q, Foo.class);
+    }
+    
+    public void testSanity2() {
+        CriteriaQuery<Foo> q = cb.createQuery(Foo.class);
+        Root<Foo> f = q.from(Foo.class);
+        q.select(f);
+        assertResult(q, Foo.class);
+    }
+    
+    public void testDeeplyNestedShape() {
+        CriteriaQuery<Tuple> q = cb.createQuery(Tuple.class);
+        Root<Foo> foo = q.from(Foo.class);
+        q.multiselect(cb.construct(Foo.class, foo.get(Foo_.flong), foo.get(Foo_.fstring)), 
+                 cb.tuple(foo, cb.array(foo.get(Foo_.fint), cb.tuple(foo.get(Foo_.fstring)))));
+        List<Tuple> result = em.createQuery(q).getResultList();
+        assertFalse(result.isEmpty());
+        Tuple tuple = result.get(0);
+        
+        assertEquals(Foo.class,   tuple.get(0).getClass());
+        assertTrue(Tuple.class.isAssignableFrom(tuple.get(1).getClass()));
+        Tuple tuple2 = (Tuple)tuple.get(1);
+        assertEquals(Foo.class,   tuple2.get(0).getClass());
+        assertEquals(Object[].class, tuple2.get(1).getClass());
+        Object[] level3 = (Object[])tuple2.get(1);
+        assertEquals(Integer.class, level3[0].getClass());
+        assertTrue(Tuple.class.isAssignableFrom(level3[1].getClass()));
+        Tuple tuple4 = (Tuple)level3[1];
+        assertEquals(String.class, tuple4.get(0).getClass());
+    }
+    
 // =============== assertions by result types ========================
     
     void assertResult(CriteriaQuery<?> q, Class<?> resultClass) {
@@ -331,8 +396,12 @@
             if (resultClass.isArray() && arrayElementClasses != null) {
                 for (int i = 0; i < arrayElementClasses.length; i++) {
                     Object element = Array.get(row, i);
+                    if (Tuple.class.isInstance(element)) {
+                        assertEquals(arrayElementClasses[i], Tuple.class.cast(element).get(0).getClass()); 
+                    } else {
                     assertTrue(i + "-th array element " + toString(arrayElementClasses[i]) + 
                        " does not match actual result " + toClass(element), arrayElementClasses[i].isInstance(element));
+                    }
                 }
             }
             if (resultClass == Tuple.class && arrayElementClasses != null) {

Modified: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/criteria/results/TestTypedResults.java Tue Aug 11 03:02:45 2009
@@ -47,7 +47,8 @@
     DateFormat df = DateFormat.getInstance(); // uses SHORT dateformat by default
 
     public void setUp() throws Exception {
-        setUp(Order.class, Item.class, Shop.class, Producer.class);
+        setUp(CLEAR_TABLES, Order.class, Item.class, Shop.class, Producer.class,
+             "openjpa.DynamicEnhancerAgent", "false");
         populate();
     }
 

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleElementImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleElementImpl.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleElementImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleElementImpl.java Tue Aug 11 03:02:45 2009
@@ -31,7 +31,6 @@
 public class TupleElementImpl<X> implements TupleElement<X> {
     private String _alias;
     protected final Class<X> _cls;
-    private X _value;
 
     protected TupleElementImpl(Class<X> cls) {
         _cls = cls;
@@ -41,22 +40,12 @@
         return _alias;
     }
 
-    protected void setAlias(String alias) {
+    protected TupleElement<X> setAlias(String alias) {
         _alias = alias;
+        return this;
     }
 
     public Class<X> getJavaType() {
         return _cls;
     }
-    
-    public X getValue() { 
-        return _value;
-    }
-    
-    @SuppressWarnings("unchecked")
-    public void setValue(Object x) {
-        // X is unknown at compile time in TupleImpl when we construct a new Tuple. 
-        // so we're stuck with this ugly cast.
-        _value = (X) x;
-    }
 }

Added: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java?rev=802984&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java (added)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java Tue Aug 11 03:02:45 2009
@@ -0,0 +1,92 @@
+/*
+ * 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.openjpa.persistence;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.Tuple;
+import javax.persistence.TupleElement;
+import javax.persistence.criteria.Selection;
+
+import org.apache.openjpa.kernel.ObjectFactory;
+
+
+/**
+ * A factory for tuples such that all instances created by a factory instance share the same TupleElements
+ * to save memory consumption.
+ * <BR>
+ * All Tuple instances created by this factory access the TupleElememts contained in this factory. 
+ * 
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
+public class TupleFactory implements ObjectFactory<Tuple> {
+    private final List<TupleElement<?>> elements;
+    
+    /**
+     * A factory of Tuple that shares the given TupleElements.
+     * 
+     */
+    public TupleFactory(List<TupleElement<?>> elems) {
+        elements = Collections.unmodifiableList(elems);
+    }
+    
+    public TupleFactory(TupleElement<?>... elems) {
+        this(Arrays.asList(elems));
+    }
+    
+    public TupleFactory(Selection<?>... elems) {
+        List<TupleElement<?>> list = new ArrayList<TupleElement<?>>();
+        for (Selection<?> s : elems)
+            list.add(s);
+        elements = Collections.unmodifiableList(list);
+    }
+    
+    public List<TupleElement<?>> getElements() {
+        return elements;
+    }
+    
+    public TupleImpl newInstance() {
+        TupleImpl impl = new TupleImpl(this);
+        return impl;
+    }
+    
+    public int getIndex(TupleElement<?> e) {
+        int i = elements.indexOf(e);
+        if (i == -1)
+            throw new IllegalArgumentException("Index " + i + " does not exist");
+        return i;
+    }
+    
+    public int getIndex(String alias) {
+        if (alias == null)
+            throw new IllegalArgumentException("null alias");
+        for (int i = 0; i < elements.size(); i++) {
+            TupleElement<?> e = elements.get(i);
+            if (alias.equals(e.getAlias()))
+                return i;
+        }
+        throw new IllegalArgumentException(alias + " not found");
+    }
+}

Propchange: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleImpl.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/TupleImpl.java Tue Aug 11 03:02:45 2009
@@ -19,167 +19,100 @@
 
 package org.apache.openjpa.persistence;
 
-import java.util.ArrayList;
+import java.lang.reflect.Method;
 import java.util.List;
 
 import javax.persistence.Tuple;
 import javax.persistence.TupleElement;
 
-import org.apache.openjpa.kernel.ExpressionStoreQuery;
+import org.apache.openjpa.kernel.Filters;
 import org.apache.openjpa.lib.util.Localizer;
 
+/**
+ * Tuple holds a set of values corresponding to a set of {@link TupleElement}.
+ * This implementation prefers index-based access. 
+ * A Tuple instance is constructed by a TupleFactory.
+ * The TupleElemets are shared across all the tuple instances.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
 public class TupleImpl implements Tuple {
     private static final Localizer _loc = Localizer.forPackage(TupleImpl.class);
-    List<TupleElement<?>> elements = new ArrayList<TupleElement<?>>();
-
+    private final TupleFactory factory;
+    private final Object[] values;
+    public static Method PUT;
+    static {
+        try {
+            PUT = TupleImpl.class.getMethod("put", new Class[]{Integer.class, Object.class});
+        } catch (Exception e) {
+        }
+    }
+    
     /**
-     * Get the value of the specified tuple element.
-     * 
-     * @param tupleElement
-     *            tuple element
-     * @return value of tuple element
-     * @throws IllegalArgumentException
-     *             if tuple element does not correspond to an element in the query result tuple
+     * Supply the factory that creates prototypes and holds the elements.
      */
+    TupleImpl(TupleFactory factory) {
+        this.factory = factory;
+        values = new Object[factory.getElements().size()];
+    }
+    
     public <X> X get(TupleElement<X> tupleElement) {
-        if (!elements.contains(tupleElement)) {
-            throw new IllegalArgumentException(_loc.get(
-                "tuple-element-not-found",
-                new Object[] { tupleElement, elements }).getMessage());
-        }
-        TupleElementImpl<X> impl = (TupleElementImpl<X>) tupleElement;
-        return impl.getValue();
+        int i = factory.getIndex(tupleElement);
+        return assertAndConvertType(""+i, values[i], tupleElement.getJavaType());
     }
 
-    /**
-     * Get the value of the tuple element to which the specified alias has been assigned.
-     * 
-     * @param alias
-     *            alias assigned to tuple element
-     * @param type
-     *            of the tuple element
-     * @return value of the tuple element
-     * @throws IllegalArgumentException
-     *             if alias does not correspond to an element in the query result tuple or element cannot be assigned to
-     *             the specified type
-     */
-    @SuppressWarnings("unchecked")
     public <X> X get(String alias, Class<X> type) {
-        if (type == null) {
-            throw new IllegalArgumentException(_loc.get("tuple-was-null", "type").getMessage());
-        }
-        Object rval = get(alias);
-        if (!type.isAssignableFrom(rval.getClass())) {
-            throw new IllegalArgumentException(_loc.get(
-                "tuple-element-wrong-type",
-                new Object[] { alias, type, rval.getClass() }).getMessage());
-        }
-        return (X) rval;
+        Object val = values[factory.getIndex(alias)];
+        return assertAndConvertType(alias, val, type);
     }
 
-    /**
-     * Get the value of the tuple element to which the specified alias has been assigned.
-     * 
-     * @param alias
-     *            alias assigned to tuple element
-     * @return value of the tuple element
-     * @throws IllegalArgumentException
-     *             if alias does not correspond to an element in the query result tuple
-     */
     public Object get(String alias) {
-        if (alias == null) {
-            // TODO MDD determine if we can support this. 
-            throw new IllegalArgumentException(_loc.get("typle-was-null", "alias").getMessage());
-        }
-        for (TupleElement<?> te : elements) {
-            if (alias.equals(te.getAlias())) {
-                return ((TupleElementImpl<?>) te).getValue();
-            }
-        }
-
-        List<String> knownAliases = new ArrayList<String>();
-        for(TupleElement<?> te : elements) { 
-            knownAliases.add(te.getAlias());
-        }
-        throw new IllegalArgumentException(_loc.get("tuple-alias-not-found",
-            new Object[] { alias, knownAliases }).getMessage());
+        return get(alias, null);
     }
 
-    /**
-     * Get the value of the element at the specified position in the result tuple. The first position is 0.
-     * 
-     * @param i
-     *            position in result tuple
-     * @param type
-     *            type of the tuple element
-     * @return value of the tuple element
-     * @throws IllegalArgumentException
-     *             if i exceeds length of result tuple or element cannot be assigned to the specified type
-     */
-    @SuppressWarnings("unchecked")
     public <X> X get(int i, Class<X> type) {
-        if (type == null) {
-            throw new IllegalArgumentException(_loc.get("tuple-was-null", "type").getMessage());
+        if (i >= values.length || i < 0) {
+            throw new IllegalArgumentException(_loc.get("tuple-exceeded-size", i, values.length).getMessage());
         }
-        Object rval = get(i);
-        if(! type.isAssignableFrom(rval.getClass())) { 
-            throw new IllegalArgumentException(_loc.get(
-                "tuple-element-wrong-type",
-                new Object[] { "position", i, type, type.getClass() }).getMessage());
-        }
-        return (X) rval;
+        Object val = values[i];
+        return assertAndConvertType(""+i, val, type);
     }
 
-    /**
-     * Get the value of the element at the specified position in the result tuple. The first position is 0.
-     * 
-     * @param i
-     *            position in result tuple
-     * @return value of the tuple element
-     * @throws IllegalArgumentException
-     *             if i exceeds length of result tuple
-     */
     public Object get(int i) {
-        if (i > elements.size()) {
-            throw new IllegalArgumentException(_loc.get("tuple-exceeded-size",
-                new Object[] { i, elements.size() }).getMessage());
-        }
-        if (i <= -1) {
-            throw new IllegalArgumentException(_loc.get("tuple-stop-thinking-in-python").getMessage());
-        }
-        return toArray()[i];
+        return get(i, null);
     }
 
-    /**
-     * Return the values of the result tuple elements as an array.
-     * 
-     * @return tuple element values
-     */
     public Object[] toArray() {
-        Object[] rval = new Object[elements.size()];
-        int i = 0;
-        for (TupleElement<?> tupleElement : elements) {
-            rval[i] = ((TupleElementImpl<?>) tupleElement).getValue();
-            i++;
-        }
-        return rval;
+        return values;
     }
 
-    /**
-     * Return the tuple elements
-     * 
-     * @return tuple elements
-     */
     public List<TupleElement<?>> getElements() {
-        return elements;
+        return factory.getElements();
     }
 
-    @SuppressWarnings("unchecked")
-    public void put(Object key, Object value) {
-        // TODO check for duplicate aliases? 
-        TupleElementImpl<?> element = new TupleElementImpl(value == null ? Object.class : value.getClass());
-        element.setAlias((String) key);
-        element.setValue(value);
-        elements.add(element);
+    /**
+     * Put the value at the given key index.
+     * This is invoked by the kernel to populate a Tuple.
+     */
+    public void put(Integer key, Object value) {
+        values[key] = value;
+    }
+    
+    /**
+     * Assert that the given value is convertible to the given type and convert.
+     * null type implies no conversion and a pure cast.
+     */
+    <X> X assertAndConvertType(String id, Object value, Class<X> type) {
+        try {
+            if (type == null || value == null) {
+                return (X) value;
+            } else {
+                return (X) Filters.convert(value, type);
+            }
+        } catch (Exception e) {
+            throw new IllegalArgumentException(_loc.get("tuple-element-wrong-type", new Object[]{id, value, 
+                value.getClass().getName(), type.getName()}).getMessage());
+        }
     }
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompoundSelections.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompoundSelections.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompoundSelections.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CompoundSelections.java Tue Aug 11 03:02:45 2009
@@ -1,18 +1,68 @@
+/*
+ * 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.openjpa.persistence.criteria;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
+import javax.persistence.Tuple;
+import javax.persistence.TupleElement;
 import javax.persistence.criteria.CompoundSelection;
 import javax.persistence.criteria.Selection;
 
+import org.apache.openjpa.kernel.FillStrategy;
+import org.apache.openjpa.kernel.ResultShape;
+import org.apache.openjpa.persistence.TupleFactory;
+import org.apache.openjpa.persistence.TupleImpl;
+
+/**
+ * Implements slection terms that are composed of other selection terms.
+ *  
+ * @author Pinaki Poddar
+ * 
+ * @since 2.0.0
+ *
+ */
 public class CompoundSelections {
+    /**
+     * Gets the strategy to fill a given compound selection.
+     * 
+     */
+    public static <X> FillStrategy<X> getFillStrategy(Selection<X> s) {
+        if (s instanceof CompoundSelectionImpl) {
+            return ((CompoundSelectionImpl<X>)s).getFillStrategy();
+        } else {
+            return new FillStrategy.Assign<X>();
+        }
+    }
+    
+    /**
+     * Abstract implementation of a selection term composed of multiple selection terms.
+     *
+     */
     private abstract static class CompoundSelectionImpl<X> extends SelectionImpl<X> implements CompoundSelection<X> {
         private final List<Selection<?>> _args;
+        
         public CompoundSelectionImpl(Class<X> cls, Selection<?>...args) {
             super(cls);
-            assertNoCompoundSelection(args);
+//            assertNoCompoundSelection(args);
             _args = args == null ? (List<Selection<?>>)Collections.EMPTY_LIST : Arrays.asList(args);
         }
         
@@ -40,8 +90,14 @@
             }
         }
 
+        public abstract FillStrategy<X> getFillStrategy();
     }
     
+    /**
+     * A compound selection which is an array of its component terms.
+     *
+     * @param <X> type must be an array
+     */
     public static class Array<X> extends CompoundSelectionImpl<X> {
         public Array(Class<X> cls, Selection<?>... terms) {
             super(cls, terms);
@@ -49,18 +105,67 @@
                 throw new IllegalArgumentException(cls + " is not an array. " + this + " needs an array");
             }
         }
+        
+        public FillStrategy<X> getFillStrategy() {
+            return new FillStrategy.Array<X>(getJavaType());
+        }
     }
     
+    /**
+     * A compound selection which is an instance constructed of its component terms.
+     *
+     * @param <X> type of the constructed instance
+     */
     public static class NewInstance<X> extends CompoundSelectionImpl<X> {
         public NewInstance(Class<X> cls, Selection<?>... selections) {
             super(cls, selections);
         }
+        
+        public FillStrategy<X> getFillStrategy() {
+            return new FillStrategy.NewInstance<X>(getJavaType());
+        }
     }
     
-    public static class Tuple<T extends javax.persistence.Tuple> extends CompoundSelectionImpl<T> {
-        public Tuple(final Class<T> cls, final Selection<?>[] selections) {
-            super(cls, selections);
+    /**
+     * A compound selection which is a Tuple composed of its component terms.
+     *
+     */
+    public static class Tuple extends CompoundSelectionImpl<javax.persistence.Tuple> {
+        public Tuple(final Selection<?>[] selections) {
+            super(javax.persistence.Tuple.class, selections);
+        }
+        
+        public FillStrategy<javax.persistence.Tuple> getFillStrategy() {
+            List<Selection<?>> terms = getCompoundSelectionItems();
+            TupleFactory factory = new TupleFactory(terms.toArray(new TupleElement[terms.size()]));
+            return new FillStrategy.Factory<javax.persistence.Tuple>(factory, TupleImpl.PUT);
         }
     }
 
+    public static class MultiSelection<T> extends CompoundSelectionImpl<T> {
+        public MultiSelection(Class<T> result, final Selection<?>[] selections) {
+            super(result, selections);
+        }
+        public FillStrategy<T> getFillStrategy() {
+            Class<?> resultClass = getJavaType();
+            List<Selection<?>> terms = getCompoundSelectionItems();
+            FillStrategy<?> strategy = null;
+            if (javax.persistence.Tuple.class.isAssignableFrom(resultClass)) {
+                TupleFactory factory = new TupleFactory(terms.toArray(new TupleElement[terms.size()]));
+                strategy = new FillStrategy.Factory<javax.persistence.Tuple>(factory,  TupleImpl.PUT);
+           } else if (resultClass == Object.class) {
+               if (terms.size() > 1) { 
+                   resultClass = Object[].class;
+                   strategy = new FillStrategy.Array<Object[]>(Object[].class);
+               } else {
+                   strategy = new FillStrategy.Assign();
+               }
+           } else {
+               strategy = resultClass.isArray() 
+                        ? new FillStrategy.Array(resultClass) 
+                        : new FillStrategy.NewInstance(resultClass);
+           } 
+            return (FillStrategy<T>)strategy;
+        }
+    }
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaBuilder.java Tue Aug 11 03:02:45 2009
@@ -48,7 +48,6 @@
 import org.apache.openjpa.kernel.exps.QueryExpressions;
 import org.apache.openjpa.kernel.exps.Value;
 import org.apache.openjpa.meta.ClassMetaData;
-import org.apache.openjpa.persistence.TupleImpl;
 import org.apache.openjpa.persistence.meta.MetamodelImpl;
 
 /**
@@ -157,16 +156,16 @@
     }
 
     public <T> Coalesce<T> coalesce() {
-        return new Expressions.Coalesce();
+        return new Expressions.Coalesce(Object.class);
     }
 
     public <Y> Expression<Y> coalesce(Expression<? extends Y> x,
         Expression<? extends Y> y) {
-    	return new Expressions.Coalesce<Y>().value(x).value(y);
+    	return new Expressions.Coalesce(x.getClass()).value(x).value(y);
     }
 
     public <Y> Expression<Y> coalesce(Expression<? extends Y> x, Y y) {
-    	return new Expressions.Coalesce<Y>().value(x).value(y);
+    	return new Expressions.Coalesce(x.getClass()).value(x).value(y);
    }
 
     public Expression<String> concat(Expression<String> x, 
@@ -560,7 +559,7 @@
     }
 
     public <R> Case<R> selectCase() {
-        return new Expressions.Case();
+        return new Expressions.Case(Object.class);
     }
 
     public <C, R> SimpleCase<C, R> selectCase(Expression<? extends C> expression) {
@@ -697,7 +696,7 @@
      *          array-valued selection item
      */
     public CompoundSelection<Tuple> tuple(Selection<?>... selections) {
-        return new CompoundSelections.Tuple(TupleImpl.class, selections);
+        return new CompoundSelections.Tuple(selections);
     }
     
     /**

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaExpressionBuilder.java Tue Aug 11 03:02:45 2009
@@ -27,6 +27,7 @@
 import java.util.Set;
 
 import javax.persistence.Tuple;
+import javax.persistence.TupleElement;
 import javax.persistence.criteria.CompoundSelection;
 import javax.persistence.criteria.Expression;
 import javax.persistence.criteria.Fetch;
@@ -37,14 +38,15 @@
 import javax.persistence.criteria.Selection;
 import javax.persistence.metamodel.Type.PersistenceType;
 
+import org.apache.openjpa.kernel.FillStrategy;
 import org.apache.openjpa.kernel.QueryOperations;
 import org.apache.openjpa.kernel.ResultShape;
-import org.apache.openjpa.kernel.ResultShape.FillStrategy;
 import org.apache.openjpa.kernel.exps.AbstractExpressionBuilder;
 import org.apache.openjpa.kernel.exps.ExpressionFactory;
 import org.apache.openjpa.kernel.exps.QueryExpressions;
 import org.apache.openjpa.kernel.exps.Value;
 import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.persistence.TupleFactory;
 import org.apache.openjpa.persistence.TupleImpl;
 import org.apache.openjpa.persistence.meta.AbstractManagedType;
 import org.apache.openjpa.persistence.meta.Members;
@@ -80,7 +82,7 @@
         exps.operation = QueryOperations.OP_SELECT;
         //exps.range = null; // Value[]
         exps.resultClass = q.getResultType();
-        exps.shape = evalResultShape(q, q.getSelectionList());
+        exps.shape = evalResultShape(q);
         exps.parameterTypes = q.getParameterTypes();
         return exps;
     }
@@ -340,31 +342,36 @@
     
     /**
      * Gets the shape of a selection item. Creates the shape if necessary.
+     * 
+     * @param q the original query
+     * @param parent the parent shape that nests this given selection
+     * @param s the selection term for which a result shape to be computed
      */
-    ResultShape<?> getShape(Selection<?> s, Map<Selection<?>, ResultShape<?>> nestedShapes) {
-        if (nestedShapes.containsKey(s)) {
-            return nestedShapes.get(s);
-        }
-        Class<?> type = s.getJavaType() == null ? Object.class : s.getJavaType();
+    ResultShape<?> getShape(CriteriaQueryImpl<?> q, ResultShape<?> parent, Selection<?> s) {
         ResultShape<?> result = null;
-        FillStrategy strategy = FillStrategy.ASSIGN;
+        Class<?> type = s.getJavaType();
+        if (type == null)
+            type = Object.class;
         if (s.isCompoundSelection()) {
-            if (s instanceof CompoundSelections.NewInstance) {
-                strategy = FillStrategy.CONSTRUCTOR;
-            } else if (s instanceof CompoundSelections.Array) {
-                strategy = FillStrategy.ARRAY;
-            } else if (s instanceof CompoundSelections.Tuple) {
-                strategy = FillStrategy.MAP;
-            }
-            result = new ResultShape(type, strategy);
-            List<Selection<?>> terms = ((CompoundSelection<?>)s).getCompoundSelectionItems();
+            CompoundSelection<?> cs = (CompoundSelection)s;
+            result = new ResultShape(s.getJavaType(), CompoundSelections.getFillStrategy(cs));
+            List<Selection<?>> terms = cs.getCompoundSelectionItems();
             for (Selection<?> term : terms) {
-                result.nest(getShape(term, nestedShapes));
+                result.nest(getShape(q, result, term));
             }
         } else {
-            result = new ResultShape(type, strategy, true);
+            if (parent.getType().isArray() && q.isMultiselect()) {
+                Class<?> componentType = parent.getType().getComponentType();
+                if (componentType == Tuple.class) {
+                    result = new ResultShape(componentType, 
+                         new FillStrategy.Factory(new TupleFactory(s), TupleImpl.PUT), false);
+                } else {
+                    result = new ResultShape(componentType, new FillStrategy.Assign(), true);
+                }
+            } else {
+                result = new ResultShape(type, new FillStrategy.Assign(), true);
+            }
         }
-        nestedShapes.put(s, result);
         return result;
     }
     
@@ -372,40 +379,30 @@
      * Builds the result shape by creating shape for the complete result and how it nests each selection terms.
      * The shape varies based on whether the terms were selected based on multiselect() or select(). 
      */
-    private ResultShape<?> evalResultShape(CriteriaQueryImpl<?> q, List<Selection<?>> selections) {
-        Map<Selection<?>, ResultShape<?>> nestedShapes = new HashMap<Selection<?>, ResultShape<?>>();
+    private ResultShape<?> evalResultShape(CriteriaQueryImpl<?> q) {
+        List<Selection<?>> selections = q.getSelectionList();
         Class<?> resultClass = q.getResultType();
-        FillStrategy strategy = FillStrategy.ASSIGN;
         ResultShape<?> result = null;
         if (q.isMultiselect()) {
-            if (Tuple.class.isAssignableFrom(resultClass)) {
-                resultClass = TupleImpl.class;
-                strategy = FillStrategy.MAP;
-           } else if (resultClass == Object.class) {
-               if (selections.size() > 1) { 
-                   resultClass = Object[].class;
-                   strategy = FillStrategy.ARRAY;
-               }
-           } else {
-               strategy = resultClass.isArray() ? FillStrategy.ARRAY : FillStrategy.CONSTRUCTOR;
-           } 
-           result = new ResultShape(resultClass, strategy);
+           result = new ResultShape(resultClass, CompoundSelections.getFillStrategy(q.getSelection()));
            for (Selection<?> term : selections) {
-               result.nest(getShape(term, nestedShapes));
+               result.nest(getShape(q, result, term));
            }
         } else { // not multiselect
+            FillStrategy<?> strategy = new FillStrategy.Assign();
             if (Tuple.class.isAssignableFrom(resultClass)) {
-                resultClass = TupleImpl.class;
-                strategy = FillStrategy.MAP;
+                TupleFactory factory = new TupleFactory(selections.toArray(new TupleElement[selections.size()]));
+                strategy = new FillStrategy.Factory<Tuple>(factory,  TupleImpl.PUT);
             }
             result = new ResultShape(resultClass, strategy);
-            if (q.getSelectionList() == null)
+            if (q.getSelectionList() == null) {
                 return result;
+            }
             if (q.getSelectionList().size() == 1) {
-                result = getShape(q.getSelectionList().get(0), nestedShapes);
+                result = getShape(q, result, q.getSelectionList().get(0));
             } else {
                 for (Selection<?> term : q.getSelectionList()) {
-                    result.nest(getShape(term, nestedShapes));
+                    result.nest(getShape(q, result, term));
                 }
             }
         }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/CriteriaQueryImpl.java Tue Aug 11 03:02:45 2009
@@ -33,6 +33,7 @@
 import java.util.TreeSet;
 
 import javax.persistence.Tuple;
+import javax.persistence.TupleElement;
 import javax.persistence.criteria.AbstractQuery;
 import javax.persistence.criteria.CompoundSelection;
 import javax.persistence.criteria.CriteriaQuery;
@@ -46,13 +47,14 @@
 import javax.persistence.metamodel.EntityType;
 
 import org.apache.commons.collections.map.LinkedMap;
+import org.apache.openjpa.kernel.FillStrategy;
 import org.apache.openjpa.kernel.ResultShape;
 import org.apache.openjpa.kernel.StoreQuery;
-import org.apache.openjpa.kernel.ResultShape.FillStrategy;
 import org.apache.openjpa.kernel.exps.Context;
 import org.apache.openjpa.kernel.exps.ExpressionFactory;
 import org.apache.openjpa.kernel.exps.QueryExpressions;
 import org.apache.openjpa.kernel.exps.Value;
+import org.apache.openjpa.persistence.TupleFactory;
 import org.apache.openjpa.persistence.TupleImpl;
 import org.apache.openjpa.persistence.meta.MetamodelImpl;
 import org.apache.openjpa.persistence.meta.Types;
@@ -76,6 +78,7 @@
     private PredicateImpl       _where;
     private List<Order>         _orders;
     private LinkedMap/*<ParameterExpression<?>, Class<?>>*/ _params;
+    private Selection<T>        _selection;
     private List<Selection<?>>  _selections;
     private List<Expression<?>> _groups;
     private PredicateImpl       _having;
@@ -83,7 +86,6 @@
     private Boolean             _distinct;
     private SubqueryImpl<?>     _delegator;
     private final Class<T>      _resultClass;
-    private boolean             _multiselect;
     
 
     // AliasContext
@@ -142,8 +144,9 @@
      * @return the item to be returned in the query result
      */
     public Selection<T> getSelection() {
-        throw new AbstractMethodError();
+        return _selection;
     }
+    
     /**
      * Specify the items that are to be returned in the query result.
      * Replaces the previously specified selection(s), if any.
@@ -187,8 +190,8 @@
      * @return the modified query
      */
     public CriteriaQuery<T> multiselect(Selection<?>... selections) {
-        _multiselect = true;
         _selections = Arrays.asList(selections); // do not telescope
+        _selection  = new CompoundSelections.MultiSelection(_resultClass, selections);
         return this;
     }
 
@@ -226,7 +229,9 @@
      * @return the selection items of the query as a list
      */
     public List<Selection<?>> getSelectionList() {
-        return _selections;
+        if (_selections == null)
+            return Collections.EMPTY_LIST;
+        return Collections.unmodifiableList(_selections);
     }
 
     public CriteriaQuery<T> groupBy(Expression<?>... grouping) {
@@ -261,12 +266,9 @@
      * @return the modified query
      */
     public CriteriaQuery<T> select(Selection<? extends T> selection) {
-        return select(new Selection<?>[]{selection});
-    }
-
-    public CriteriaQuery<T> select(Selection<?>... selections) {
-        _multiselect = false;
-        _selections = Arrays.asList(selections);
+        _selection = (Selection<T>)selection;
+        _selections = new ArrayList<Selection<?>>();
+        _selections.add(selection);
         return this;
     }
 
@@ -540,6 +542,6 @@
     }
     
     boolean isMultiselect() {
-        return _multiselect;
+        return _selection instanceof CompoundSelections.MultiSelection;
     }
 }

Modified: openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java (original)
+++ openjpa/trunk/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/criteria/Expressions.java Tue Aug 11 03:02:45 2009
@@ -882,10 +882,6 @@
     public static class Coalesce<T> extends ExpressionImpl<T> implements QueryBuilder.Coalesce<T> {
         private final List<Expression<? extends T>> values = new ArrayList<Expression<? extends T>>();
         
-        public Coalesce() {
-            super(null);
-        }
-        
         public Coalesce(Class<T> cls) {
             super(cls);
         }
@@ -1043,10 +1039,6 @@
         private final List<Expression<Boolean>> whens     = new ArrayList<Expression<Boolean>>();
         private Expression<? extends T> otherwise;
 
-        public Case() {
-            super(null);
-        }
-
         public Case(Class<T> cls) {
             super(cls);
         }
@@ -1093,10 +1085,6 @@
         private Expression<? extends R> otherwise;
         private Expression<C> caseOperand;
 
-        public SimpleCase() {
-            super(null);
-        }
-
         public SimpleCase(Class<R> cls) {
             super(cls);
         }

Modified: openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties (original)
+++ openjpa/trunk/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties Tue Aug 11 03:02:45 2009
@@ -217,9 +217,8 @@
 param-no-key: {0} has either a name nor a position as identifier. 	
 tuple-element-not-found: TupleElement "{0}" "{1}"  was not found in this Tuple. Contents of the Tuple: {2}.
 tuple-was-null: Input argument {0} was null. Unable to proceed.
-tuple-element-wrong-type: TupleElement type did not match for {0} "{1}". Provided type "{2}" , actual type "{3}"
+tuple-element-wrong-type: TupleElement {0} of value {1} of actual type {2} can not be converted to {3}.
 tuple-alias-not-found: Alias "{0}" was not found in this tuple. Aliases found : "{1}"
-tuple-exceeded-size : Attempt to read TupleElement {0} when there are only {1} elements available
-tuple-stop-thinking-in-python: Currently we do not support negative indexes into a Tuple. 
+tuple-exceeded-size : Attempt to access TupleElement at illegal index {0}. There are only {1} elements available.
 create-emf-error: Failed to create a provider for "{0}".
 

Modified: openjpa/trunk/openjpa-persistence/src/test/java/org/apache/openjpa/persistence/TestTupleImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence/src/test/java/org/apache/openjpa/persistence/TestTupleImpl.java?rev=802984&r1=802983&r2=802984&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence/src/test/java/org/apache/openjpa/persistence/TestTupleImpl.java (original)
+++ openjpa/trunk/openjpa-persistence/src/test/java/org/apache/openjpa/persistence/TestTupleImpl.java Tue Aug 11 03:02:45 2009
@@ -23,6 +23,7 @@
 
 import javax.persistence.Tuple;
 import javax.persistence.TupleElement;
+import javax.persistence.criteria.Selection;
 
 import org.apache.openjpa.lib.util.Localizer;
 
@@ -66,12 +67,18 @@
      * @return
      */
     protected TupleImpl getTuple() {
-        TupleImpl tuple = new TupleImpl();
-        tuple.put("alias1", _order);
-        tuple.put("alias2", _product);
-        tuple.put("alias3", _item);
-        tuple.put("alias4", _store);
-        tuple.put("alias5", _urgentOrder);
+        TupleElement<Order> order = new TupleElementImpl<Order>(Order.class).setAlias("alias1"); 
+        TupleElement<Product> product = new TupleElementImpl<Product>(Product.class).setAlias("alias2");
+        TupleElement<Item> item = new TupleElementImpl<Item>(Item.class).setAlias("alias3");
+        TupleElement<Store> store = new TupleElementImpl<Store>(Store.class).setAlias("alias4");
+        TupleElement<UrgentOrder> urgentOrder = new TupleElementImpl<UrgentOrder>(UrgentOrder.class).setAlias("alias5");
+        TupleFactory factory = new TupleFactory(order, product, item, store, urgentOrder);
+        TupleImpl tuple = factory.newInstance();
+        tuple.put(0, _order);
+        tuple.put(1, _product);
+        tuple.put(2, _item);
+        tuple.put(3, _store);
+        tuple.put(4, _urgentOrder);
         return tuple;
     }
 
@@ -81,7 +88,6 @@
         assertEquals(_item, tuple.get(2));
         assertEquals(_store, tuple.get(3));
         assertEquals(_urgentOrder, tuple.get(4));
-        // TODO MDD more tests
     }
 
     public void testGetIntNegativeValueThrowsException() {
@@ -208,12 +214,6 @@
         }
     }
 
-    public void testGetTupleElement() {
-        for (TupleElement<?> element : tuple.getElements()) {
-            assertEquals(((TupleElementImpl) element).getValue(), tuple.get(element));
-        }
-    }
-
     public void testToArray() {
         Object[] objects = tuple.toArray();
         assertEquals(5, objects.length);



Mime
View raw message