001 /*
002 GRANITE DATA SERVICES
003 Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004
005 This file is part of Granite Data Services.
006
007 Granite Data Services is free software; you can redistribute it and/or modify
008 it under the terms of the GNU Library General Public License as published by
009 the Free Software Foundation; either version 2 of the License, or (at your
010 option) any later version.
011
012 Granite Data Services is distributed in the hope that it will be useful, but
013 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015 for more details.
016
017 You should have received a copy of the GNU Library General Public License
018 along with this library; if not, see <http://www.gnu.org/licenses/>.
019 */
020
021 package org.granite.util;
022
023 import java.beans.Introspector;
024 import java.beans.PropertyDescriptor;
025 import java.lang.reflect.Array;
026 import java.lang.reflect.Constructor;
027 import java.lang.reflect.Field;
028 import java.lang.reflect.GenericArrayType;
029 import java.lang.reflect.InvocationTargetException;
030 import java.lang.reflect.Method;
031 import java.lang.reflect.Modifier;
032 import java.lang.reflect.ParameterizedType;
033 import java.lang.reflect.Type;
034 import java.lang.reflect.TypeVariable;
035 import java.lang.reflect.WildcardType;
036 import java.net.MalformedURLException;
037 import java.net.URL;
038 import java.util.Collections;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Set;
042
043 /**
044 * @author Franck WOLFF
045 */
046 public abstract class ClassUtil {
047
048 public static Object newInstance(String type)
049 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
050 return forName(type).newInstance();
051 }
052
053 public static <T> T newInstance(String type, Class<T> cast)
054 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
055 return forName(type, cast).newInstance();
056 }
057
058 public static Object newInstance(String type, Class<?>[] argsClass, Object[] argsValues)
059 throws ClassNotFoundException, InstantiationException, IllegalAccessException {
060 return newInstance(forName(type), argsClass, argsValues);
061 }
062
063 @SuppressWarnings("unchecked")
064 public static <T> T newInstance(Class<?> type, Class<T> cast)
065 throws InstantiationException, IllegalAccessException {
066 return (T)type.newInstance();
067 }
068
069 public static <T> T newInstance(Class<T> type, Class<?>[] argsClass, Object[] argsValues)
070 throws InstantiationException, IllegalAccessException {
071 T instance = null;
072 try {
073 Constructor<T> constructorDef = type.getConstructor(argsClass);
074 instance = constructorDef.newInstance(argsValues);
075 } catch (SecurityException e) {
076 throw new InstantiationException(e.getMessage());
077 } catch (NoSuchMethodException e) {
078 throw new InstantiationException(e.getMessage());
079 } catch (IllegalArgumentException e) {
080 throw new InstantiationException(e.getMessage());
081 } catch (InvocationTargetException e) {
082 throw new InstantiationException(e.getMessage());
083 }
084 return instance;
085 }
086
087 public static Class<?> forName(String type) throws ClassNotFoundException {
088 try {
089 return ClassUtil.class.getClassLoader().loadClass(type);
090 }
091 catch (ClassNotFoundException e) {
092 return Thread.currentThread().getContextClassLoader().loadClass(type);
093 }
094 }
095
096 @SuppressWarnings("unchecked")
097 public static <T> Class<T> forName(String type, Class<T> cast) throws ClassNotFoundException {
098 try {
099 return (Class<T>)ClassUtil.class.getClassLoader().loadClass(type);
100 }
101 catch (ClassNotFoundException e) {
102 return (Class<T>)Thread.currentThread().getContextClassLoader().loadClass(type);
103 }
104 }
105
106 public static Constructor<?> getConstructor(String type, Class<?>[] paramTypes)
107 throws ClassNotFoundException, NoSuchMethodException {
108 return getConstructor(forName(type), paramTypes);
109 }
110
111 public static <T> Constructor<T> getConstructor(Class<T> type, Class<?>[] paramTypes)
112 throws NoSuchMethodException {
113 return type.getConstructor(paramTypes);
114 }
115
116 public static <T> List<T> emptyList(Class<T> type) {
117 return Collections.emptyList();
118 }
119
120 public static <T> Set<T> emptySet(Class<T> type) {
121 return Collections.emptySet();
122 }
123
124 public static <T, U> Map<T, U> emptyMap(Class<T> keyType, Class<U> valueType) {
125 return Collections.emptyMap();
126 }
127
128 public static boolean isPrimitive(Type type) {
129 return type instanceof Class<?> && ((Class<?>)type).isPrimitive();
130 }
131
132 public static Class<?> classOfType(Type type) {
133 if (type instanceof Class<?>)
134 return (Class<?>)type;
135 if (type instanceof ParameterizedType)
136 return (Class<?>)((ParameterizedType)type).getRawType();
137 if (type instanceof WildcardType) {
138 // Forget lower bounds and only deal with first upper bound...
139 Type[] ubs = ((WildcardType)type).getUpperBounds();
140 if (ubs.length > 0)
141 return classOfType(ubs[0]);
142 }
143 if (type instanceof GenericArrayType) {
144 Class<?> ct = classOfType(((GenericArrayType)type).getGenericComponentType());
145 return (ct != null ? Array.newInstance(ct, 0).getClass() : Object[].class);
146 }
147 if (type instanceof TypeVariable<?>) {
148 // Only deal with first (upper) bound...
149 Type[] ubs = ((TypeVariable<?>)type).getBounds();
150 if (ubs.length > 0)
151 return classOfType(ubs[0]);
152 }
153 // Should never append...
154 return Object.class;
155 }
156
157 public static Type getBoundType(TypeVariable<?> typeVariable) {
158 Type[] ubs = typeVariable.getBounds();
159 if (ubs.length > 0)
160 return ubs[0];
161
162 // should never happen...
163 if (typeVariable.getGenericDeclaration() instanceof Type)
164 return (Type)typeVariable.getGenericDeclaration();
165 return typeVariable;
166 }
167
168 public static String getPackageName(Class<?> clazz) {
169 return clazz.getPackage() != null ? clazz.getPackage().getName() : "";
170 }
171
172 public static PropertyDescriptor[] getProperties(Class<?> clazz) {
173 try {
174 PropertyDescriptor[] properties = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
175 Field[] fields = clazz.getDeclaredFields();
176 for (Field field : fields) {
177 if (Boolean.class.equals(field.getType())) {
178 boolean found = false;
179 for (PropertyDescriptor property : properties) {
180 if (property.getName().equals(field.getName())) {
181 found = true;
182 if (property.getReadMethod() == null) {
183 try {
184 Method readMethod = clazz.getDeclaredMethod(getIsMethodName(field.getName()));
185 if (Modifier.isPublic(readMethod.getModifiers()) && !Modifier.isStatic(readMethod.getModifiers()))
186 property.setReadMethod(readMethod);
187 }
188 catch (NoSuchMethodException e) {
189 }
190 }
191 break;
192 }
193 }
194 if (!found) {
195 try {
196 Method readMethod = clazz.getDeclaredMethod(getIsMethodName(field.getName()));
197 if (Modifier.isPublic(readMethod.getModifiers()) && !Modifier.isStatic(readMethod.getModifiers())) {
198 PropertyDescriptor[] propertiesTmp = new PropertyDescriptor[properties.length + 1];
199 System.arraycopy(properties, 0, propertiesTmp, 0, properties.length);
200 propertiesTmp[properties.length] = new PropertyDescriptor(field.getName(), readMethod, null);
201 properties = propertiesTmp;
202 }
203 }
204 catch (NoSuchMethodException e) {
205 }
206 }
207 }
208 }
209 return properties;
210 } catch (Exception e) {
211 throw new RuntimeException("Could not introspect properties of class: " + clazz, e);
212 }
213 }
214
215 private static String getIsMethodName(String name) {
216 return "is" + name.substring(0, 1).toUpperCase() + name.substring(1);
217 }
218
219 public static ClassLoader getClassLoader(Class<?> clazz) {
220 return (clazz.getClassLoader() != null ? clazz.getClassLoader() : ClassLoader.getSystemClassLoader());
221 }
222
223 public static URL findResource(Class<?> clazz) {
224 if (clazz.isArray())
225 clazz = clazz.getComponentType();
226 if (clazz.isPrimitive())
227 return null;
228 URL url = getClassLoader(clazz).getResource(toResourceName(clazz));
229 String path = url.toString();
230 if (path.indexOf(' ') != -1) {
231 try {
232 url = new URL(path.replace(" ", "%20"));
233 } catch (MalformedURLException e) {
234 // should never happen...
235 }
236 }
237 return url;
238 }
239
240 public static String toResourceName(Class<?> clazz) {
241 return clazz.getName().replace('.', '/').concat(".class");
242 }
243
244 public static String getMethodSignature(Method method) {
245 StringBuilder sb = new StringBuilder();
246 sb.append(method.getName()).append('(');
247 Class<?>[] params = method.getParameterTypes();
248 for (int i = 0; i < params.length; i++) {
249 if (i > 0)
250 sb.append(',');
251 sb.append(getTypeSignature(params[i]));
252 }
253 sb.append(')');
254 return sb.toString();
255 }
256
257 public static String getTypeSignature(Class<?> type) {
258 if (type.isArray()) {
259 try {
260 int dimensions = 1;
261 Class<?> clazz = type.getComponentType();
262 while (clazz.isArray()) {
263 dimensions++;
264 clazz = clazz.getComponentType();
265 }
266
267 StringBuffer sb = new StringBuffer(clazz.getName());
268 while (dimensions-- > 0)
269 sb.append("[]");
270 return sb.toString();
271 } catch (Throwable e) {
272 // fallback...
273 }
274 }
275 return type.getName();
276 }
277
278 public static Method getMethod(Class<?> clazz, String signature) throws NoSuchMethodException {
279 signature = StringUtil.removeSpaces(signature);
280
281 if (!signature.endsWith(")"))
282 signature += "()";
283
284 for (Method method : clazz.getMethods()) {
285 if (signature.equals(getMethodSignature(method)))
286 return method;
287 }
288
289 throw new NoSuchMethodException("Could not find method: " + signature + " in class: " + clazz);
290 }
291 }