View Javadoc

1   /*
2    * Copyright 2004-2007 Brian McCallister
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of 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,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.skife.jdbi.v2;
18  
19  import org.skife.jdbi.v2.tweak.ResultSetMapper;
20  
21  import java.beans.BeanInfo;
22  import java.beans.IntrospectionException;
23  import java.beans.Introspector;
24  import java.beans.PropertyDescriptor;
25  import java.lang.reflect.InvocationTargetException;
26  import java.math.BigDecimal;
27  import java.sql.ResultSet;
28  import java.sql.ResultSetMetaData;
29  import java.sql.SQLException;
30  import java.sql.Time;
31  import java.sql.Timestamp;
32  import java.util.Date;
33  import java.util.HashMap;
34  import java.util.Map;
35  
36  /**
37   * A result set mapper which maps the fields in a statement into a JavaBean. This uses
38   * the JDK's built in bean mapping facilities, so it does not support nested properties.
39   */
40  public class BeanMapper<T> implements ResultSetMapper<T>
41  {
42      private final Class<T> type;
43  	private final Map<String, PropertyDescriptor> properties = new HashMap<String, PropertyDescriptor>();
44  
45  	public BeanMapper(Class<T> type)
46      {
47          this.type = type;
48          try
49          {
50              BeanInfo info = Introspector.getBeanInfo(type);
51  
52  			for (PropertyDescriptor descriptor : info.getPropertyDescriptors())
53  			{
54  				properties.put(descriptor.getName().toLowerCase(), descriptor);
55  			}
56  		}
57          catch (IntrospectionException e)
58          {
59              throw new IllegalArgumentException(e);
60          }
61  	}
62  
63  	public T map(int row, ResultSet rs, StatementContext ctx)
64  			throws SQLException
65  	{
66  		T bean;
67          try
68          {
69              bean = type.newInstance();
70          }
71          catch (Exception e)
72          {
73              throw new IllegalArgumentException(String.format("A bean, %s, was mapped " +
74                                                               "which was not instantiable", type.getName()),
75                                                 e);
76          }
77  
78  		ResultSetMetaData metadata = rs.getMetaData();
79  
80  		for (int i = 1; i <= metadata.getColumnCount(); ++i) {
81  			String name = metadata.getColumnName(i).toLowerCase();
82  
83  			PropertyDescriptor descriptor = properties.get(name);
84  
85  			if (descriptor != null) {
86  				Class<?> type = descriptor.getPropertyType();
87  
88  				Object value;
89  
90  				if (type.isAssignableFrom(Boolean.class) || type.isAssignableFrom(boolean.class)) {
91  					value = rs.getBoolean(i);
92  				}
93  				else if (type.isAssignableFrom(Byte.class) || type.isAssignableFrom(byte.class)) {
94  					value = rs.getByte(i);
95  				}
96  				else if (type.isAssignableFrom(Short.class) || type.isAssignableFrom(short.class)) {
97  					value = rs.getShort(i);
98  				}
99  				else if (type.isAssignableFrom(Integer.class) || type.isAssignableFrom(int.class)) {
100 					value = rs.getInt(i);
101 				}
102 				else if (type.isAssignableFrom(Long.class) || type.isAssignableFrom(long.class)) {
103 					value = rs.getLong(i);
104 				}
105 				else if (type.isAssignableFrom(Float.class) || type.isAssignableFrom(float.class)) {
106 					value = rs.getFloat(i);
107 				}
108 				else if (type.isAssignableFrom(Double.class) || type.isAssignableFrom(double.class)) {
109 					value = rs.getDouble(i);
110 				}
111 				else if (type.isAssignableFrom(BigDecimal.class)) {
112 					value = rs.getBigDecimal(i);
113 				}
114 				else if (type.isAssignableFrom(Timestamp.class)) {
115 					value = rs.getTimestamp(i);
116 				}
117 				else if (type.isAssignableFrom(Time.class)) {
118 					value = rs.getTime(i);
119 				}
120 				else if (type.isAssignableFrom(Date.class)) {
121 					value = rs.getDate(i);
122 				}
123 				else if (type.isAssignableFrom(String.class)) {
124 					value = rs.getString(i);
125 				}
126 				else {
127 					value = rs.getObject(i);
128 				}
129 
130 				if (rs.wasNull() && !type.isPrimitive()) {
131 					value = null;
132 				}
133 
134 				try
135 				{
136 					descriptor.getWriteMethod().invoke(bean, value);
137 				}
138 				catch (IllegalAccessException e)
139 				{
140 					throw new IllegalArgumentException(String.format("Unable to access setter for " +
141 																	 "property, %s", name), e);
142 				}
143 				catch (InvocationTargetException e)
144 				{
145 					throw new IllegalArgumentException(String.format("Invocation target exception trying to " +
146 																	 "invoker setter for the %s property", name), e);
147 				}
148         catch (NullPointerException e)
149         {
150           throw new IllegalArgumentException(String.format("No appropriate method to " +
151                                    "write value %s ", value.toString()), e);
152         }
153 
154 			}
155 		}
156 
157         return bean;
158 	}
159 }
160