Changeset 28 for trunk/fmgVen/src/com/fmguler/ven/QueryMapper.java
- Timestamp:
- Feb 9, 2011, 10:53:45 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/fmgVen/src/com/fmguler/ven/QueryMapper.java
r23 r28 18 18 package com.fmguler.ven; 19 19 20 import com.fmguler.ven.util.Convert; 21 import com.fmguler.ven.util.VenList; 22 import java.beans.PropertyDescriptor; 23 import java.sql.ResultSet; 24 import java.sql.SQLException; 25 import java.util.ArrayList; 26 import java.util.Date; 27 import java.util.HashSet; 28 import java.util.Iterator; 29 import java.util.LinkedList; 20 30 import java.util.List; 31 import java.util.Map; 32 import java.util.Set; 21 33 import javax.sql.DataSource; 34 import org.springframework.beans.BeanWrapper; 35 import org.springframework.beans.BeanWrapperImpl; 36 import org.springframework.jdbc.core.RowCallbackHandler; 22 37 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 23 38 … … 28 43 public class QueryMapper { 29 44 private NamedParameterJdbcTemplate template; 45 private Set domainPackages; 46 private Set dbClasses; 47 private boolean debug = true; 30 48 31 public List list() { 32 return null; 49 public QueryMapper() { 50 domainPackages = new HashSet(); 51 dbClasses = new HashSet(); 52 //the predefined database classes; 53 this.dbClasses.add(Integer.class); 54 this.dbClasses.add(String.class); 55 this.dbClasses.add(Date.class); 56 this.dbClasses.add(Double.class); 57 this.dbClasses.add(Boolean.class); 33 58 } 34 59 35 //SETTERS------------------------------------------------------------------- 60 /** 61 * Executes the specified query setting the specified parameters, 62 * and maps the results to the instances of the specified objectClass. 63 * @param query select SQL query in the conventional format 64 * @param parameters named query parameter values 65 * @param objectClass the type of the object to be mapped 66 * @return the list of mapped objects 67 */ 68 public List list(String query, Map parameters, final Class objectClass) { 69 long t1 = System.currentTimeMillis(); 70 final List results = new LinkedList(); 71 final String tableName = Convert.toDB(Convert.toSimpleName(objectClass.getName())); 72 final Set columns = new HashSet(); 73 74 template.query(query, parameters, new RowCallbackHandler() { 75 public void processRow(ResultSet rs) throws SQLException { 76 enumerateColumns(columns, rs); 77 mapRecursively(rs, columns, tableName, objectClass, results); 78 } 79 }); 80 81 System.out.println("Ven - list time = " + (System.currentTimeMillis() - t1)); 82 return results; 83 } 84 85 //-------------------------------------------------------------------------- 86 //PRIVATE METHODS 87 //recursively map the resultSet to the object and add to the list 88 protected void mapRecursively(ResultSet rs, Set columns, String tableName, Class objectClass, List parentList) { 89 try { 90 if (!columns.contains(tableName + "_id")) return; //this object does not exist in the columns 91 Object id = rs.getObject(tableName + "_id"); 92 if (id == null) return; //this object exists in the columns but null, probably because of left join 93 94 //create bean wrapper for the object class 95 BeanWrapper wr = new BeanWrapperImpl(objectClass); //already caches class introspection (CachedIntrospectionResults.forClass()) 96 wr.setPropertyValue("id", id); //set the id property 97 Object object = wr.getWrappedInstance(); 98 boolean map = true; 99 100 //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) 101 for (Iterator it = parentList.iterator(); it.hasNext();) { 102 Object objectInList = (Object)it.next(); 103 if (objectIdEquals(objectInList, id)) { 104 wr.setWrappedInstance(objectInList); //already exists in the list, use that instance 105 map = false; // and do not map again 106 break; 107 } 108 } 109 if (map) parentList.add(object); //could not find in the parent list, add the new object 110 111 PropertyDescriptor[] pdArr = wr.getPropertyDescriptors(); 112 for (int i = 0; i < pdArr.length; i++) { 113 PropertyDescriptor pd = pdArr[i]; 114 Class fieldClass = pd.getPropertyType(); //field class 115 String fieldName = Convert.toDB(pd.getName()); //field name 116 Object fieldValue = wr.getPropertyValue(pd.getName()); 117 String columnName = tableName + "_" + fieldName; 118 119 //database class (primitive property) 120 if (map && dbClasses.contains(fieldClass)) { 121 if (columns.contains(columnName)) { 122 if (debug) System.out.println(">>field is found: " + columnName); 123 wr.setPropertyValue(pd.getName(), rs.getObject(columnName)); 124 } else { 125 if (debug) System.out.println("--field not found: " + columnName); 126 } 127 } 128 129 //many to one association (object property) 130 if (map && fieldClass.getPackage() != null && domainPackages.contains(fieldClass.getPackage().getName())) { 131 if (columns.contains(columnName + "_id")) { 132 if (debug) System.out.println(">>object is found " + columnName); 133 List list = new ArrayList(1); //we know there will be single result 134 mapRecursively(rs, columns, columnName, fieldClass, list); 135 if (list.size() > 0) wr.setPropertyValue(pd.getName(), list.get(0)); 136 } else { 137 if (debug) System.out.println("--object not found: " + columnName); 138 } 139 } 140 141 //one to many association (list property) 142 if (fieldValue instanceof List) { //Note: here recurring row's list property is mapped and add to parent's list 143 if (columns.contains(columnName + "_id")) { 144 Class elementClass = VenList.findElementClass((List)fieldValue); 145 if (debug) System.out.println(">>list is found " + columnName); 146 mapRecursively(rs, columns, columnName, elementClass, (List)fieldValue); 147 } else { 148 if (debug) System.out.println("--list not found: " + columnName); 149 } 150 } 151 } 152 } catch (Exception ex) { 153 if (debug) { 154 System.out.println("Ven - error while mapping row; "); 155 ex.printStackTrace(); 156 } 157 } 158 } 159 160 //enumerate columns from the resultset 161 private void enumerateColumns(Set columns, ResultSet rs) throws SQLException { 162 if (!columns.isEmpty()) return; 163 for (int i = 1; i < rs.getMetaData().getColumnCount() + 1; i++) { 164 columns.add(rs.getMetaData().getColumnName(i)); 165 } 166 } 167 168 //check if the specified objects are the same entity (according to id fields) 169 private boolean objectIdEquals(Object object, Object id) { 170 //return obj1.equals(obj2); //objects need to implement equals() 171 //TODO: more efficient (invoke getId method) 172 BeanWrapper wr = new BeanWrapperImpl(object); 173 return id.equals(wr.getPropertyValue("id")); 174 } 175 176 //-------------------------------------------------------------------------- 177 //SETTERS 178 /** 179 * @param dataSource used for accessing database 180 */ 36 181 public void setDataSource(DataSource dataSource) { 37 182 if (dataSource == null) throw new RuntimeException("fmgVen - DataSource cannot be null"); … … 39 184 } 40 185 41 public void addDomainPackage(String domainPackage){ 42 186 /** 187 * Add the domain packages that will be considered persistent 188 * @param domainPackage the domain package 189 */ 190 public void addDomainPackage(String domainPackage) { 191 domainPackages.add(domainPackage); 43 192 } 44 193 }
Note: See TracChangeset
for help on using the changeset viewer.