001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.xbean.recipe; 018 019 import java.lang.reflect.Array; 020 import java.lang.reflect.Constructor; 021 import java.lang.reflect.GenericArrayType; 022 import java.lang.reflect.Modifier; 023 import java.lang.reflect.ParameterizedType; 024 import java.lang.reflect.Type; 025 import java.lang.reflect.TypeVariable; 026 import java.util.ArrayList; 027 import java.util.Collections; 028 import java.util.Comparator; 029 import java.util.LinkedList; 030 import java.util.List; 031 import java.util.Map; 032 033 import org.apache.xbean.propertyeditor.PropertyEditors; 034 035 /** 036 * @version $Rev: 6687 $ $Date: 2005-12-28T21:08:56.733437Z $ 037 */ 038 public final class RecipeHelper { 039 private RecipeHelper() { 040 } 041 042 public static Recipe getCaller() { 043 LinkedList<Recipe> stack = ExecutionContext.getContext().getStack(); 044 if (stack.size() < 2) { 045 return null; 046 } 047 return stack.get(stack.size() - 2); 048 } 049 050 public static Class loadClass(String name) throws ClassNotFoundException { 051 ClassLoader classLoader = ExecutionContext.getContext().getClassLoader(); 052 Class<?> type = Class.forName(name, true, classLoader); 053 return type; 054 } 055 056 public static boolean hasDefaultConstructor(Class type) { 057 if (!Modifier.isPublic(type.getModifiers())) { 058 return false; 059 } 060 if (Modifier.isAbstract(type.getModifiers())) { 061 return false; 062 } 063 Constructor[] constructors = type.getConstructors(); 064 for (Constructor constructor : constructors) { 065 if (Modifier.isPublic(constructor.getModifiers()) && 066 constructor.getParameterTypes().length == 0) { 067 return true; 068 } 069 } 070 return false; 071 } 072 073 public static boolean isSimpleType(Object o) { 074 return o == null || 075 o instanceof Boolean || 076 o instanceof Character || 077 o instanceof Byte || 078 o instanceof Short || 079 o instanceof Integer || 080 o instanceof Long || 081 o instanceof Float || 082 o instanceof Double || 083 o instanceof String || 084 o instanceof Recipe; 085 086 } 087 088 public static <K,V> List<Map.Entry<K,V>> prioritizeProperties(Map<K,V> properties) { 089 ArrayList<Map.Entry<K,V>> entries = new ArrayList<Map.Entry<K,V>>(properties.entrySet()); 090 Collections.sort(entries, new RecipeComparator()); 091 return entries; 092 } 093 094 public static boolean isInstance(Type t, Object instance) { 095 Class type = toClass(t); 096 if (type.isPrimitive()) { 097 // for primitives the insance can't be null 098 if (instance == null) { 099 return false; 100 } 101 102 // verify instance is the correct wrapper type 103 if (type.equals(boolean.class)) { 104 return instance instanceof Boolean; 105 } else if (type.equals(char.class)) { 106 return instance instanceof Character; 107 } else if (type.equals(byte.class)) { 108 return instance instanceof Byte; 109 } else if (type.equals(short.class)) { 110 return instance instanceof Short; 111 } else if (type.equals(int.class)) { 112 return instance instanceof Integer; 113 } else if (type.equals(long.class)) { 114 return instance instanceof Long; 115 } else if (type.equals(float.class)) { 116 return instance instanceof Float; 117 } else if (type.equals(double.class)) { 118 return instance instanceof Double; 119 } else { 120 throw new AssertionError("Invalid primitve type: " + type); 121 } 122 } 123 124 return instance == null || type.isInstance(instance); 125 } 126 127 public static boolean isConvertable(Type type, Object propertyValue) { 128 if (propertyValue instanceof Recipe) { 129 Recipe recipe = (Recipe) propertyValue; 130 return recipe.canCreate(type); 131 } 132 return (propertyValue instanceof String && PropertyEditors.canConvert(toClass(type))); 133 } 134 135 public static boolean isAssignableFrom(Class expected, Class actual) { 136 if (expected == null) return true; 137 138 if (expected.isPrimitive()) { 139 // verify actual is the correct wrapper type 140 if (expected.equals(boolean.class)) { 141 return actual.equals(Boolean.class); 142 } else if (expected.equals(char.class)) { 143 return actual.equals(Character.class); 144 } else if (expected.equals(byte.class)) { 145 return actual.equals(Byte.class); 146 } else if (expected.equals(short.class)) { 147 return actual.equals(Short.class); 148 } else if (expected.equals(int.class)) { 149 return actual.equals(Integer.class); 150 } else if (expected.equals(long.class)) { 151 return actual.equals(Long.class); 152 } else if (expected.equals(float.class)) { 153 return actual.equals(Float.class); 154 } else if (expected.equals(double.class)) { 155 return actual.equals(Double.class); 156 } else { 157 throw new AssertionError("Invalid primitve type: " + expected); 158 } 159 } 160 161 return expected.isAssignableFrom(actual); 162 } 163 164 public static Object convert(Type expectedType, Object value, boolean lazyRefAllowed) { 165 if (value instanceof Recipe) { 166 Recipe recipe = (Recipe) value; 167 value = recipe.create(expectedType, lazyRefAllowed); 168 } 169 170 if (value instanceof String && (expectedType != Object.class)) { 171 String stringValue = (String) value; 172 value = PropertyEditors.getValue(expectedType, stringValue); 173 } 174 return value; 175 } 176 177 public static boolean isAssignableFrom(List<? extends Class<?>> expectedTypes, List<? extends Class<?>> actualTypes) { 178 if (expectedTypes.size() != actualTypes.size()) { 179 return false; 180 } 181 for (int i = 0; i < expectedTypes.size(); i++) { 182 Class expectedType = expectedTypes.get(i); 183 Class actualType = actualTypes.get(i); 184 if (expectedType != actualType && !isAssignableFrom(expectedType, actualType)) { 185 return false; 186 } 187 } 188 return true; 189 } 190 191 public static boolean isAssignable(Type expectedType, Type actualType) { 192 Class expectedClass = toClass(expectedType); 193 Class actualClass = toClass(actualType); 194 return expectedClass.isAssignableFrom(actualClass); 195 } 196 197 public static Class toClass(Type type) { 198 // GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType 199 if (type instanceof Class) { 200 Class clazz = (Class) type; 201 return clazz; 202 } else if (type instanceof GenericArrayType) { 203 GenericArrayType arrayType = (GenericArrayType) type; 204 Class componentType = toClass(arrayType.getGenericComponentType()); 205 return Array.newInstance(componentType, 0).getClass(); 206 } else if (type instanceof ParameterizedType) { 207 ParameterizedType parameterizedType = (ParameterizedType) type; 208 return toClass(parameterizedType.getRawType()); 209 } else { 210 return Object.class; 211 } 212 } 213 214 public static class RecipeComparator implements Comparator<Object> { 215 public int compare(Object left, Object right) { 216 if (!(left instanceof Recipe) && !(right instanceof Recipe)) return 0; 217 if (left instanceof Recipe && !(right instanceof Recipe)) return 1; 218 if (!(left instanceof Recipe) && right instanceof Recipe) return -1; 219 220 float leftPriority = ((Recipe) left).getPriority(); 221 float rightPriority = ((Recipe) right).getPriority(); 222 223 if (leftPriority > rightPriority) return 1; 224 if (leftPriority < rightPriority) return -1; 225 return 0; 226 } 227 } 228 229 public static Type[] getTypeParameters(Class desiredType, Type type) { 230 if (type instanceof Class) { 231 Class rawClass = (Class) type; 232 233 // if this is the collection class we're done 234 if (desiredType.equals(type)) { 235 return null; 236 } 237 238 for (Type intf : rawClass.getGenericInterfaces()) { 239 Type[] collectionType = getTypeParameters(desiredType, intf); 240 if (collectionType != null) { 241 return collectionType; 242 } 243 } 244 245 Type[] collectionType = getTypeParameters(desiredType, rawClass.getGenericSuperclass()); 246 return collectionType; 247 } else if (type instanceof ParameterizedType) { 248 ParameterizedType parameterizedType = (ParameterizedType) type; 249 250 Type rawType = parameterizedType.getRawType(); 251 if (desiredType.equals(rawType)) { 252 Type[] argument = parameterizedType.getActualTypeArguments(); 253 return argument; 254 } 255 Type[] collectionTypes = getTypeParameters(desiredType,rawType); 256 if (collectionTypes != null) { 257 for (int i = 0; i < collectionTypes.length; i++) { 258 if (collectionTypes[i] instanceof TypeVariable) { 259 TypeVariable typeVariable = (TypeVariable) collectionTypes[i]; 260 TypeVariable[] rawTypeParams = ((Class) rawType).getTypeParameters(); 261 for (int j = 0; j < rawTypeParams.length; j++) { 262 if (typeVariable.getName().equals(rawTypeParams[j].getName())) { 263 collectionTypes[i] = parameterizedType.getActualTypeArguments()[j]; 264 } 265 } 266 } 267 } 268 } 269 return collectionTypes; 270 } 271 return null; 272 } 273 }