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 }