001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.hivemind.util;
016
017 import java.lang.reflect.Constructor;
018 import java.lang.reflect.InvocationTargetException;
019 import java.lang.reflect.Modifier;
020 import java.util.ArrayList;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.Map;
024
025 import org.apache.hivemind.ApplicationRuntimeException;
026
027 /**
028 * Static methods for invoking constructors.
029 *
030 * @author Howard Lewis Ship
031 */
032 public class ConstructorUtils
033 {
034
035 /**
036 * Map from primitive type to wrapper type.
037 */
038 private static final Map _primitiveMap = new HashMap();
039
040 static
041 {
042 _primitiveMap.put(boolean.class, Boolean.class);
043 _primitiveMap.put(byte.class, Byte.class);
044 _primitiveMap.put(char.class, Character.class);
045 _primitiveMap.put(short.class, Short.class);
046 _primitiveMap.put(int.class, Integer.class);
047 _primitiveMap.put(long.class, Long.class);
048 _primitiveMap.put(float.class, Float.class);
049 _primitiveMap.put(double.class, Double.class);
050 }
051
052 // Prevent instantiation
053
054 private ConstructorUtils()
055 {
056 }
057
058 /**
059 * Searches for a constructor matching against the provided arguments.
060 *
061 * @param targetClass
062 * the class to be instantiated
063 * @param parameters
064 * the parameters to pass to the constructor (may be null or empty)
065 * @return the new instance
066 * @throws ApplicationRuntimeException
067 * on any failure
068 */
069 public static Object invokeConstructor(Class targetClass, Object[] parameters)
070 {
071 if (parameters == null)
072 parameters = new Object[0];
073
074 Class[] parameterTypes = new Class[parameters.length];
075
076 for (int i = 0; i < parameters.length; i++)
077 parameterTypes[i] = parameters[i] == null ? null : parameters[i].getClass();
078
079 return invokeMatchingConstructor(targetClass, parameterTypes, parameters);
080 }
081
082 private static Object invokeMatchingConstructor(Class targetClass, Class[] parameterTypes,
083 Object[] parameters)
084 {
085 Constructor[] constructors = targetClass.getConstructors();
086
087 for (int i = 0; i < constructors.length; i++)
088 {
089 Constructor c = constructors[i];
090
091 if (isMatch(c, parameterTypes))
092 return invoke(c, parameters);
093 }
094
095 throw new ApplicationRuntimeException(UtilMessages.noMatchingConstructor(targetClass), null);
096 }
097
098 private static boolean isMatch(Constructor c, Class[] types)
099 {
100 Class[] actualTypes = c.getParameterTypes();
101
102 if (actualTypes.length != types.length)
103 return false;
104
105 for (int i = 0; i < types.length; i++)
106 {
107 if (types[i] == null && !actualTypes[i].isPrimitive())
108 continue;
109
110 if (!isCompatible(actualTypes[i], types[i]))
111 return false;
112 }
113
114 return true;
115 }
116
117 public static boolean isCompatible(Class actualType, Class parameterType)
118 {
119 if (actualType.isAssignableFrom(parameterType))
120 return true;
121
122 // Reflection fudges the assignment of a wrapper class to a primitive
123 // type ... we check for that the hard way.
124
125 if (actualType.isPrimitive())
126 {
127 Class wrapperClass = (Class) _primitiveMap.get(actualType);
128
129 return wrapperClass.isAssignableFrom(parameterType);
130 }
131
132 return false;
133 }
134
135 public static Object invoke(Constructor c, Object[] parameters)
136 {
137 try
138 {
139 return c.newInstance(parameters);
140 }
141 catch (InvocationTargetException ex)
142 {
143 Throwable cause = ex.getTargetException();
144
145 throw new ApplicationRuntimeException(UtilMessages.invokeFailed(c, cause), null, cause);
146 }
147 catch (Exception ex)
148 {
149 throw new ApplicationRuntimeException(UtilMessages.invokeFailed(c, ex), null, ex);
150 }
151 }
152
153 public static List getConstructorsOfLength(final Class clazz, final int length)
154 {
155 List fixedLengthConstructors = new ArrayList(1);
156
157 Constructor[] constructors = clazz.getDeclaredConstructors();
158
159 for (int i = 0; i < constructors.length; i++)
160 {
161 if (!Modifier.isPublic(constructors[i].getModifiers()))
162 continue;
163
164 Class[] parameterTypes = constructors[i].getParameterTypes();
165
166 if (parameterTypes.length == length)
167 fixedLengthConstructors.add(constructors[i]);
168 }
169
170 return fixedLengthConstructors;
171 }
172 }