1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.reflect.reflectors;
17
18 import java.lang.reflect.Modifier;
19 import java.util.Calendar;
20 import java.util.GregorianCalendar;
21 import java.util.Map;
22 import java.util.Set;
23
24 import net.sf.composite.util.ObjectUtils;
25 import net.sf.morph.reflect.InstantiatingReflector;
26 import net.sf.morph.reflect.ReflectionException;
27 import net.sf.morph.util.Assert;
28 import net.sf.morph.util.ClassUtils;
29 import net.sf.morph.util.TransformerUtils;
30 import net.sf.morph.util.TypeMap;
31
32 /**
33 * A basic instantiating reflector that allows an arbitrary number of requested
34 * class types to be mapped to instantiated types. The default instance of this
35 * class can instantiate common interfaces such as {@link java.util.Calendar}
36 * and {@link java.lang.CharSequence}.
37 *
38 * @author Matt Sgarlata
39 * @since Feb 27, 2005
40 */
41 public class SimpleInstantiatingReflector extends BaseReflector implements InstantiatingReflector {
42
43 private Map requestedToInstantiatedTypeMap;
44
45 /**
46 * Create a new SimpleInstantiatingReflector.
47 */
48 public SimpleInstantiatingReflector() {
49 super();
50 }
51
52 /**
53 * Create a new SimpleInstantiatingReflector for a single type.
54 * @param instantiatedType
55 */
56 public SimpleInstantiatingReflector(Class instantiatedType) {
57 this(instantiatedType, instantiatedType);
58 }
59
60 /**
61 * Create a new SimpleInstantiatingReflector for a single type mapping.
62 * @param requestedType
63 * @param instantiatedType
64 */
65 public SimpleInstantiatingReflector(Class requestedType, Class instantiatedType) {
66 super();
67 setRequestedType(requestedType);
68 setInstantiatedType(instantiatedType);
69 }
70
71 /**
72 * Create a new SimpleInstantiatingReflector for the specified type map.
73 * @param requestedToInstantiatedClassMap
74 */
75 public SimpleInstantiatingReflector(Map requestedToInstantiatedClassMap) {
76 super();
77 this.requestedToInstantiatedTypeMap = requestedToInstantiatedClassMap;
78 }
79
80 /**
81 * {@inheritDoc}
82 * @see net.sf.morph.reflect.reflectors.BaseReflector#getReflectableClassesImpl()
83 */
84 protected Class[] getReflectableClassesImpl() throws Exception {
85 Set reflectableClasses = getRequestedToInstantiatedTypeMap().keySet();
86 return (Class[]) reflectableClasses.toArray(new Class[reflectableClasses.size()]);
87 }
88
89 /**
90 * {@inheritDoc}
91 * @see net.sf.morph.reflect.reflectors.BaseReflector#newInstanceImpl(java.lang.Class, java.lang.Object)
92 */
93 protected Object newInstanceImpl(Class requestedType, Object parameters) throws Exception {
94 Class typeToInstantiate = TransformerUtils.getMappedDestinationType(
95 getRequestedToInstantiatedTypeMap(), requestedType);
96 if (typeToInstantiate == null) {
97 throw new Exception("Unable to instantiate " + requestedType);
98 }
99 return super.newInstanceImpl(typeToInstantiate, parameters);
100 }
101
102 /**
103 * Returns the instantiated type if only a single mapping of requested type
104 * to instantiated type has been specified.
105 *
106 * @return the instantiated type, if one has been specified or <br>
107 * <code>null</code> if no instantiated type has been specified
108 * @throws IllegalStateException
109 * if there is more than one mapping of requested type to
110 * instantiated type
111 */
112 public final Class getInstantiatedType() {
113 if (ObjectUtils.isEmpty(getRequestedToInstantiatedTypeMap())) {
114 return null;
115 }
116 if (getRequestedToInstantiatedTypeMap().size() == 1) {
117 return (Class) getRequestedToInstantiatedTypeMap().values().iterator().next();
118 }
119 throw new IllegalStateException("This reflector has multiple "
120 + "mappings of requested types to instantiated types, so a "
121 + "single instantiated type cannot be returned. The mappings "
122 + "are " + getRequestedToInstantiatedTypeMap());
123 }
124
125 /**
126 * Sets the instantiated type if only a single mapping of requested type to
127 * instantiated type is needed.
128 *
129 * @param instantiatedType
130 * the instantiated type
131 */
132 public final void setInstantiatedType(Class instantiatedType) {
133 if (instantiatedType == null || instantiatedType.isInterface() || Modifier.isAbstract(instantiatedType.getModifiers())) {
134 throw new IllegalArgumentException("instantiatedType " + instantiatedType);
135 }
136 Class requestedType;
137 try {
138 requestedType = getRequestedType();
139 }
140 catch (IllegalStateException e) {
141 requestedType = null;
142 }
143 getRequestedToInstantiatedTypeMap().clear();
144 getRequestedToInstantiatedTypeMap().put(requestedType, instantiatedType);
145 }
146
147 /**
148 * Returns the requested type if only a single mapping of requested type to
149 * instantiated type has been specified.
150 *
151 * @return the requested type, if one has been specified or <br>
152 * <code>null</code> if no requested type has been specified
153 * @throws IllegalStateException
154 * if there is more than one mapping of requested type to
155 * instantiated type
156 */
157 public final Class getRequestedType() {
158 if (ObjectUtils.isEmpty(getRequestedToInstantiatedTypeMap())) {
159 return null;
160 }
161 if (getRequestedToInstantiatedTypeMap().size() == 1) {
162 return (Class) getRequestedToInstantiatedTypeMap().keySet().iterator().next();
163 }
164 throw new IllegalStateException("This reflector has multiple "
165 + "mappings of requested types to instantiated types, so a "
166 + "single requested type cannot be returned. The mappings "
167 + "are " + getRequestedToInstantiatedTypeMap());
168 }
169
170 /**
171 * Sets the requested type if only a single mapping of requested type to
172 * instantiated type is needed.
173 *
174 * @param requestedType
175 * the requested type
176 */
177 public final void setRequestedType(Class requestedType) {
178 Assert.notNull(requestedType, "requestedType");
179 Class instantiatedType;
180 try {
181 instantiatedType = getInstantiatedType();
182 }
183 catch (IllegalStateException e) {
184 instantiatedType = null;
185 }
186 getRequestedToInstantiatedTypeMap().clear();
187 getRequestedToInstantiatedTypeMap().put(requestedType, instantiatedType);
188 }
189
190 /**
191 * Returns the mapping of requested types to instantiated types.
192 *
193 * @return the mapping of requested types to instantiated types
194 */
195 public synchronized Map getRequestedToInstantiatedTypeMap() {
196 if (requestedToInstantiatedTypeMap == null) {
197 Map map = new TypeMap();
198 map.put(Calendar.class, GregorianCalendar.class);
199
200 if (ClassUtils.isJdk14OrHigherPresent()) {
201 try {
202 map.put(Class.forName("java.lang.CharSequence"), StringBuffer.class);
203 }
204
205
206 catch (ClassNotFoundException e) {
207 throw new ReflectionException(e);
208 }
209 }
210 setRequestedToInstantiatedTypeMap(map);
211 }
212 return requestedToInstantiatedTypeMap;
213 }
214
215 /**
216 * Sets the mapping of requested types to instantiated types.
217 *
218 * @param interfaceToImplementationMap
219 * the mapping of requested types to instantiated types
220 */
221 public synchronized void setRequestedToInstantiatedTypeMap(
222 Map interfaceToImplementationMap) {
223 this.requestedToInstantiatedTypeMap = new TypeMap(interfaceToImplementationMap);
224 }
225 }