View Javadoc

1   /*
2    * Copyright 2004-2005 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at
7    * 
8    * http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations under
14   * the License.
15   */
16  package net.sf.morph.reflect.reflectors;
17  
18  import java.sql.Blob;
19  import java.sql.Clob;
20  import java.sql.ResultSet;
21  import java.sql.ResultSetMetaData;
22  import java.util.Iterator;
23  
24  import org.springframework.jdbc.support.JdbcUtils;
25  
26  import net.sf.morph.reflect.BeanReflector;
27  import net.sf.morph.reflect.ContainerReflector;
28  import net.sf.morph.reflect.support.ResultSetIterator;
29  import net.sf.morph.transform.TransformationException;
30  
31  /**
32   * <p>
33   * Exposes the information in a ResultSet. This reflector can function both as a
34   * container reflector and as a bean reflector. When functionining a container
35   * reflector, this reflector exposes the rows in a ResultSet. As a bean
36   * reflector, this reflector exposes the column names from a particular row of a
37   * ResultSet as properties. The column names are always converted to all
38   * lowercase.
39   * </p>
40   * 
41   * <p>
42   * Note: Code from the {@link #getImpl(Object, String)} method was taken from
43   * Spring's {@link JdbcUtils} class.
44   * </p>
45   * 
46   * @author Matt Sgarlata
47   * @since Dec 18, 2004
48   */
49  public class ResultSetReflector
50  	extends BaseBeanReflector
51  	implements BeanReflector, ContainerReflector {
52  	
53  	private static final Class[] REFLECTABLE_TYPES = new Class[] {
54  		ResultSet.class
55  	};
56  	
57  	private ResultSet getResultSet(Object bean) {
58  		return (ResultSet) bean;
59  	}
60  	
61  	private ResultSetMetaData getMetaData(Object bean) throws Exception {
62  		return getResultSet(bean).getMetaData();
63  	}
64  
65  // container reflector methods	
66  	
67  	protected Class getContainedTypeImpl(Class clazz) throws Exception {
68  		return ResultSet.class;
69  	}
70  	protected Iterator getIteratorImpl(Object container) throws Exception {
71  		return new ResultSetIterator((ResultSet) container);
72  	}
73  
74  // bean reflector methods	
75  	
76  	private int getIndexForColumn(Object bean, String propertyName) throws Exception {
77  		int numColumns = getMetaData(bean).getColumnCount();
78  		String lowerCasePropertyName = propertyName.toLowerCase();
79  		for (int i=1; i<numColumns; i++) {
80  			if (lowerCasePropertyName.equals(getMetaData(bean).getColumnLabel(i).toLowerCase())) {
81  				return i;
82  			}
83  		}
84  		throw new TransformationException("The propertyName you specified '" + propertyName + "' was not found to be a column in the given ResultSet");
85  	}
86  
87  	protected String[] getPropertyNamesImpl(Object bean) throws Exception {
88  		ResultSetMetaData meta = getMetaData(bean);
89  		int numColumns = meta.getColumnCount();
90  		String[] propertyNames = new String[numColumns];
91  		for (int i=0; i<propertyNames.length; i++) {
92  			propertyNames[i] = meta.getColumnName(i+1).toLowerCase();
93  		}
94  		return propertyNames;
95  	}
96  
97  	protected Class getTypeImpl(Object bean, String propertyName)
98  		throws Exception {
99  		return Class.forName(getMetaData(bean).getColumnClassName(
100 			getIndexForColumn(bean, propertyName)));
101 	}
102 
103 	protected boolean isWriteableImpl(Object bean, String propertyName)
104 		throws Exception {
105 		return getMetaData(bean).isWritable(
106 			getIndexForColumn(bean, propertyName));
107 	}
108 
109 	/**
110 	 * NOTE: Code copied here from Spring's
111 	 * {@link org.springframework.jdbc.support.JdbcUtils} class.
112 	 */
113 	protected Object getImpl(Object bean, String propertyName) throws Exception {
114 		ResultSet rs = getResultSet(bean);
115 		Object obj = rs.getObject(propertyName);		
116 		if (obj instanceof Blob) {
117 			obj = rs.getBytes(propertyName);
118 		}
119 		else if (obj instanceof Clob) {
120 			obj = rs.getString(propertyName);
121 		}
122 		else if (obj != null && obj.getClass().getName().startsWith("oracle.sql.TIMESTAMP")) {
123 			obj = rs.getTimestamp(propertyName);
124 		}
125 		else if (obj != null && obj.getClass().getName().startsWith("oracle.sql.DATE")) {
126 			int index = getIndexForColumn(bean, propertyName);
127 			String metaDataClassName = rs.getMetaData().getColumnClassName(index);
128 			if ("java.sql.Timestamp".equals(metaDataClassName) ||
129 					"oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
130 				obj = rs.getTimestamp(propertyName);
131 			}
132 			else {
133 				obj = rs.getDate(propertyName);
134 			}
135 		}
136 		else if (obj != null && obj instanceof java.sql.Date) {
137 			int index = getIndexForColumn(bean, propertyName);
138 			if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
139 				obj = rs.getTimestamp(propertyName);
140 			}
141 		}
142 		return obj;
143 	}
144 
145 	protected void setImpl(Object bean, String propertyName, Object value)
146 		throws Exception {
147 		getResultSet(bean).updateObject(propertyName, value);
148 	}
149 
150 	protected Class[] getReflectableClassesImpl() throws Exception {
151 		return REFLECTABLE_TYPES;
152 	}
153 
154 	public boolean isStrictlyTyped() {
155 		return true;
156 	}
157 
158 }