Index: trunk/fmgVen/src/com/fmguler/ven/QueryGenerator.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/QueryGenerator.java	(revision 27)
+++ trunk/fmgVen/src/com/fmguler/ven/QueryGenerator.java	(revision 28)
@@ -19,7 +19,10 @@
 
 import com.fmguler.ven.util.Convert;
+import com.fmguler.ven.util.VenList;
 import java.beans.PropertyDescriptor;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 import org.springframework.beans.BeanWrapper;
@@ -33,4 +36,5 @@
     private Set domainPackages;
     private Set dbClasses;
+    private boolean debug = true;
 
     public QueryGenerator() {
@@ -45,6 +49,20 @@
     }
 
-    public String generateSelectQuery() {
-        return null;
+    /**
+     * Generates select query for the specified object class and specified joins.
+     * @param joins set of joins that the query will contain
+     * @param objectClass the object class to select from
+     * @return the select SQL query
+     */
+    public String generateSelectQuery(Class objectClass, Set joins) {
+        long t1 = System.currentTimeMillis();
+        String objectName = Convert.toSimpleName(objectClass.getName());
+        String tableName = Convert.toDB(objectName);
+        StringBuffer selectClause = new StringBuffer("select ");
+        StringBuffer fromClause = new StringBuffer("from " + tableName);
+        generateRecursively(0, tableName, objectName, objectClass, joins, selectClause, fromClause);
+        selectClause.append(" 1=1");
+        if (debug) System.out.println("Ven - query generation time = " + (System.currentTimeMillis() - t1));
+        return selectClause.toString() + " \n" + fromClause.toString();
     }
 
@@ -129,10 +147,10 @@
      * @return the delete SQL query
      */
-    public String generateDeleteQuery(Class objectClass){
+    public String generateDeleteQuery(Class objectClass) {
         StringBuffer query = new StringBuffer();
         query.append("delete from ").append(Convert.toDB(Convert.toSimpleName(objectClass.getName()))).append(" where id = :id;");
         return query.toString();
     }
-        
+
     /**
      * Generates sequence query for the specified object
@@ -147,5 +165,73 @@
 
     //--------------------------------------------------------------------------
+    //PRIVATE METHODS
+    //recursively generate select query
+    private void generateRecursively(int level, String tableName, String objectPath, Class objectClass, Set joins, StringBuffer selectClause, StringBuffer fromClause) {
+        BeanWrapper wr = new BeanWrapperImpl(objectClass);
+        PropertyDescriptor[] pdArr = wr.getPropertyDescriptors();
+
+        for (int i = 0; i < pdArr.length; i++) {
+            Class fieldClass = pdArr[i].getPropertyType(); //field class
+            String fieldName = pdArr[i].getName(); //field name
+            Object fieldValue = wr.getPropertyValue(fieldName);
+            String columnName = Convert.toDB(pdArr[i].getName()); //column name
+
+            //direct database class (Integer, String, Date, etc)
+            if (dbClasses.contains(fieldClass)) {
+                selectClause.append(tableName).append(".").append(columnName).append(" as ").append(tableName).append("_").append(columnName); //column
+                selectClause.append(", ");
+            }
+
+            //many to one association (object property)
+            if (fieldClass.getPackage() != null && domainPackages.contains(fieldClass.getPackage().getName()) && joinsContain(joins, objectPath + "." + fieldName)) {
+                String joinTableAlias = tableName + "_" + columnName; //alias for table to join since there can be multiple joins to the same table
+                String joinTable = Convert.toDB(Convert.toSimpleName(fieldClass.getName())); //table to join
+                fromClause.append(" left join ").append(joinTable).append(" ").append(joinTableAlias);
+                fromClause.append(" on ").append(joinTableAlias).append(".id = ").append(tableName).append(".").append(columnName).append("_id");
+                generateRecursively(++level, joinTableAlias, objectPath + "." + fieldName, fieldClass, joins, selectClause, fromClause);
+            }
+
+            //one to many association (list property)
+            if (fieldValue instanceof List && joinsContain(joins, objectPath + "." + fieldName)) {
+                Class elementClass = VenList.findElementClass((List)fieldValue);
+                String joinTableAlias = tableName + "_" + columnName; //alias for table to join since there can be multiple joins to the same table
+                String joinTable = Convert.toDB(Convert.toSimpleName(elementClass.getName())); //table to join
+                String joinField = Convert.toDB(findJoinField((List)fieldValue)); //field to join
+                fromClause.append(" left join ").append(joinTable).append(" ").append(joinTableAlias);
+                fromClause.append(" on ").append(joinTableAlias).append(".").append(joinField).append("_id = ").append(tableName).append(".id");
+                generateRecursively(++level, joinTableAlias, objectPath + "." + fieldName, elementClass, joins, selectClause, fromClause);
+            }
+        }
+    }
+
+    //check if the joins contain the specified join
+    private boolean joinsContain(Set joins, String join) {
+        Iterator it = joins.iterator();
+        while (it.hasNext()) {
+            String str = (String)it.next();
+            if (str.startsWith(join)) {
+                if (str.length() == join.length()) return true;
+                else if (str.charAt(join.length()) == '.') return true;
+            }
+        }
+        return false;
+    }
+
+    //return the join field of the elements in the list
+    private String findJoinField(List list) {
+        if (list instanceof VenList) {
+            return ((VenList)list).getJoinField();
+        } else {
+            //find according to 1.5 generic or some convention (e.g. parent_obj_id)
+            return null;
+        }
+    }
+
+    //--------------------------------------------------------------------------
     //SETTERS
+    /**
+     * Add the domain packages that will be considered persistent
+     * @param domainPackage the domain package
+     */
     public void addDomainPackage(String domainPackage) {
         domainPackages.add(domainPackage);
Index: trunk/fmgVen/src/com/fmguler/ven/QueryMapper.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/QueryMapper.java	(revision 27)
+++ trunk/fmgVen/src/com/fmguler/ven/QueryMapper.java	(revision 28)
@@ -18,6 +18,21 @@
 package com.fmguler.ven;
 
+import com.fmguler.ven.util.Convert;
+import com.fmguler.ven.util.VenList;
+import java.beans.PropertyDescriptor;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import javax.sql.DataSource;
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.jdbc.core.RowCallbackHandler;
 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
 
@@ -28,10 +43,140 @@
 public class QueryMapper {
     private NamedParameterJdbcTemplate template;
+    private Set domainPackages;
+    private Set dbClasses;
+    private boolean debug = true;
 
-    public List list() {
-        return null;
+    public QueryMapper() {
+        domainPackages = new HashSet();
+        dbClasses = new HashSet();
+        //the predefined database classes;
+        this.dbClasses.add(Integer.class);
+        this.dbClasses.add(String.class);
+        this.dbClasses.add(Date.class);
+        this.dbClasses.add(Double.class);
+        this.dbClasses.add(Boolean.class);
     }
 
-    //SETTERS-------------------------------------------------------------------
+    /**
+     * Executes the specified query setting the specified parameters,
+     * and maps the results to the instances of the specified objectClass.
+     * @param query select SQL query in the conventional format
+     * @param parameters named query parameter values
+     * @param objectClass the type of the object to be mapped
+     * @return the list of mapped objects
+     */
+    public List list(String query, Map parameters, final Class objectClass) {
+        long t1 = System.currentTimeMillis();
+        final List results = new LinkedList();
+        final String tableName = Convert.toDB(Convert.toSimpleName(objectClass.getName()));
+        final Set columns = new HashSet();
+
+        template.query(query, parameters, new RowCallbackHandler() {
+            public void processRow(ResultSet rs) throws SQLException {
+                enumerateColumns(columns, rs);
+                mapRecursively(rs, columns, tableName, objectClass, results);
+            }
+        });
+
+        System.out.println("Ven - list time = " + (System.currentTimeMillis() - t1));
+        return results;
+    }
+
+    //--------------------------------------------------------------------------
+    //PRIVATE METHODS
+    //recursively map the resultSet to the object and add to the list
+    protected void mapRecursively(ResultSet rs, Set columns, String tableName, Class objectClass, List parentList) {
+        try {
+            if (!columns.contains(tableName + "_id")) return; //this object does not exist in the columns
+            Object id = rs.getObject(tableName + "_id");
+            if (id == null) return; //this object exists in the columns but null, probably because of left join
+
+            //create bean wrapper for the object class
+            BeanWrapper wr = new BeanWrapperImpl(objectClass); //already caches class introspection (CachedIntrospectionResults.forClass())
+            wr.setPropertyValue("id", id); //set the id property
+            Object object = wr.getWrappedInstance();
+            boolean map = true;
+
+            //check if this object exists in the parent list (since SQL joins are cartesian products, do not create new object if this row is just the same as previous)
+            for (Iterator it = parentList.iterator(); it.hasNext();) {
+                Object objectInList = (Object)it.next();
+                if (objectIdEquals(objectInList, id)) {
+                    wr.setWrappedInstance(objectInList); //already exists in the list, use that instance
+                    map = false; // and do not map again
+                    break;
+                }
+            }
+            if (map) parentList.add(object); //could not find in the parent list, add the new object
+
+            PropertyDescriptor[] pdArr = wr.getPropertyDescriptors();
+            for (int i = 0; i < pdArr.length; i++) {
+                PropertyDescriptor pd = pdArr[i];
+                Class fieldClass = pd.getPropertyType(); //field class
+                String fieldName = Convert.toDB(pd.getName()); //field name
+                Object fieldValue = wr.getPropertyValue(pd.getName());
+                String columnName = tableName + "_" + fieldName;
+
+                //database class (primitive property)
+                if (map && dbClasses.contains(fieldClass)) {
+                    if (columns.contains(columnName)) {
+                        if (debug) System.out.println(">>field is found: " + columnName);
+                        wr.setPropertyValue(pd.getName(), rs.getObject(columnName));
+                    } else {
+                        if (debug) System.out.println("--field not found: " + columnName);
+                    }
+                }
+
+                //many to one association (object property)
+                if (map && fieldClass.getPackage() != null && domainPackages.contains(fieldClass.getPackage().getName())) {
+                    if (columns.contains(columnName + "_id")) {
+                        if (debug) System.out.println(">>object is found " + columnName);
+                        List list = new ArrayList(1); //we know there will be single result
+                        mapRecursively(rs, columns, columnName, fieldClass, list);
+                        if (list.size() > 0) wr.setPropertyValue(pd.getName(), list.get(0));
+                    } else {
+                        if (debug) System.out.println("--object not found: " + columnName);
+                    }
+                }
+
+                //one to many association (list property)
+                if (fieldValue instanceof List) { //Note: here recurring row's list property is mapped and add to parent's list
+                    if (columns.contains(columnName + "_id")) {
+                        Class elementClass = VenList.findElementClass((List)fieldValue);
+                        if (debug) System.out.println(">>list is found " + columnName);
+                        mapRecursively(rs, columns, columnName, elementClass, (List)fieldValue);
+                    } else {
+                        if (debug) System.out.println("--list not found: " + columnName);
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            if (debug) {
+                System.out.println("Ven - error while mapping row; ");
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    //enumerate columns from the resultset
+    private void enumerateColumns(Set columns, ResultSet rs) throws SQLException {
+        if (!columns.isEmpty()) return;
+        for (int i = 1; i < rs.getMetaData().getColumnCount() + 1; i++) {
+            columns.add(rs.getMetaData().getColumnName(i));
+        }
+    }
+
+    //check if the specified objects are the same entity (according to id fields)
+    private boolean objectIdEquals(Object object, Object id) {
+        //return obj1.equals(obj2); //objects need to implement equals()
+        //TODO: more efficient (invoke getId method)
+        BeanWrapper wr = new BeanWrapperImpl(object);
+        return id.equals(wr.getPropertyValue("id"));
+    }
+
+    //--------------------------------------------------------------------------
+    //SETTERS
+    /**
+     * @param dataSource used for accessing database
+     */
     public void setDataSource(DataSource dataSource) {
         if (dataSource == null) throw new RuntimeException("fmgVen - DataSource cannot be null");
@@ -39,6 +184,10 @@
     }
 
-    public void addDomainPackage(String domainPackage){
-
+    /**
+     * Add the domain packages that will be considered persistent
+     * @param domainPackage the domain package
+     */
+    public void addDomainPackage(String domainPackage) {
+        domainPackages.add(domainPackage);
     }
 }
Index: trunk/fmgVen/src/com/fmguler/ven/Ven.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/Ven.java	(revision 27)
+++ trunk/fmgVen/src/com/fmguler/ven/Ven.java	(revision 28)
@@ -18,7 +18,9 @@
 package com.fmguler.ven;
 
+import com.fmguler.ven.util.Convert;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import javax.sql.DataSource;
 import org.springframework.beans.BeanWrapper;
@@ -36,4 +38,5 @@
     private QueryGenerator generator;
     private QueryMapper mapper;
+    private boolean debug = true;
 
     public Ven() {
@@ -50,6 +53,16 @@
     }
 
-    public Object get(int id, Class objectClass) {
-        return null;
+    public Object get(int id, Class objectClass, Set joins) {
+        String query = generator.generateSelectQuery(objectClass, joins);
+        query += " where 1=1 and " + Convert.toDB(Convert.toSimpleName(objectClass.getName())) + ".id = :___id ";
+
+        Map paramMap = new HashMap();
+        paramMap.put("___id", new Integer(id));
+        if (debug) System.out.println("Ven - SQL: " + query);
+
+        List result = mapper.list(query, paramMap, objectClass);
+        if (result.isEmpty()) return null;
+        if (result.size() > 1) System.out.println("Ven - WARNING >> get(id) returns more than one row");
+        return result.get(0);
     }
 
@@ -114,4 +127,5 @@
         if (dataSource == null) throw new RuntimeException("fmgVen - DataSource cannot be null");
         this.template = new NamedParameterJdbcTemplate(dataSource);
+        mapper.setDataSource(dataSource);
     }
 
Index: trunk/fmgVen/src/com/fmguler/ven/util/VenList.java
===================================================================
--- trunk/fmgVen/src/com/fmguler/ven/util/VenList.java	(revision 28)
+++ trunk/fmgVen/src/com/fmguler/ven/util/VenList.java	(revision 28)
@@ -0,0 +1,88 @@
+/*
+ *  fmgVen - A Convention over Configuration Java ORM Tool
+ *  Copyright 2011 Fatih Mehmet Güler
+ * 
+ *  Licensed 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.
+ *  under the License.
+ */
+package com.fmguler.ven.util;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A Simple Linked List which informs the type of its elements.
+ * @author Fatih Mehmet Güler
+ */
+public class VenList extends LinkedList {
+    private Class elementClass;
+    private String joinField;
+
+    /**
+     * Creates new instance of VenList
+     */
+    public VenList() {
+    }
+
+    /**
+     * Creates new instance of VenList, specifying the type of elements
+     * @param elementClass the type of elements of this list
+     */
+    public VenList(Class elementClass) {
+        this.elementClass = elementClass;
+    }
+
+    /**
+     * Creates new instance of VenList, specifying the type of elements and the join field
+     * @param elementClass the type of elements of this list
+     * @param joinField the field which refers to the parent object
+     */
+    public VenList(Class elementClass, String joinField) {
+        this.elementClass = elementClass;
+        this.joinField = joinField;
+    }
+
+    /**
+     * Returns the type of the elements in this list.
+     * @return element type
+     */
+    public Class getElementClass() {
+        return elementClass;
+    }
+
+    /**
+     * Returns the field in the element class which refers the parent object
+     * @return element join field
+     */
+    public String getJoinField() {
+        return joinField;
+    }
+
+    /**
+     * Return the class of the elements in the list
+     * @param list the list
+     * @return the element class in the list
+     */
+    public static Class findElementClass(List list) {
+        if (list.size() > 0) {
+            Object elem = list.get(0);
+            return elem.getClass();
+        }
+        if (list instanceof VenList) {
+            return ((VenList)list).getElementClass();
+        } else {
+            //find according to 1.5 generic or some convention (e.g. xyzList -> xyz)
+            return null;
+        }
+    }
+}
