GlueGen v2.6.0-rc-20250712
GlueGen, Native Binding Generator for Java™ (public API).
ReflectionUtil.java
Go to the documentation of this file.
1/*
2 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (c) 2010 JogAmp Community. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * - Redistribution of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * - Redistribution in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of Sun Microsystems, Inc. or the names of
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * This software is provided "AS IS," without a warranty of any kind. ALL
21 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
22 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
23 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
24 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
25 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
26 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
27 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
28 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
29 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
30 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
31 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
32 *
33 * You acknowledge that this software is not designed or intended for use
34 * in the design, construction, operation or maintenance of any nuclear
35 * facility.
36 */
37
38package com.jogamp.common.util;
39
40import java.lang.reflect.Constructor;
41import java.lang.reflect.InvocationTargetException;
42import java.lang.reflect.Method;
43import java.util.HashMap;
44import java.util.Iterator;
45import java.util.Locale;
46import java.util.Map;
47import java.util.Map.Entry;
48import java.util.Set;
49
50import jogamp.common.Debug;
51
52import com.jogamp.common.ExceptionUtils;
53import com.jogamp.common.JogampRuntimeException;
54import com.jogamp.common.os.Clock;
55
56public final class ReflectionUtil {
57
58 public static final boolean DEBUG;
59 public static final boolean DEBUG_STATS_FORNAME;
60
61 private static final Object forNameLock;
62 private static final Map<String, ClassNameLookup> forNameStats;
63 private static int forNameCount = 0;
64 private static long forNameNanoCosts = 0;
65
66 static {
67 Debug.initSingleton();
68 DEBUG = Debug.debug("ReflectionUtil");
69 DEBUG_STATS_FORNAME = PropertyAccess.isPropertyDefined("jogamp.debug.ReflectionUtil.forNameStats", true);
71 forNameLock = new Object();
72 forNameStats = new HashMap<String, ClassNameLookup>();
73 } else {
74 forNameLock = null;
75 forNameStats = null;
76 }
77 }
78
79 public static class AWTNames {
80 public static final String ComponentClass = "java.awt.Component" ;
81 public static final String GraphicsEnvironmentClass = "java.awt.GraphicsEnvironment";
82 public static final String isHeadlessMethod = "isHeadless";
83 }
84 private static final Class<?>[] zeroTypes = new Class[0];
85
86 private static class ClassNameLookup {
87 public ClassNameLookup(final String name) {
88 this.name = name;
89 this.nanoCosts = 0;
90 this.count = 0;
91 }
92 public final String name;
93 public long nanoCosts;
94 public int count;
95 @Override
96 public String toString() {
97 return String.format((Locale)null, "%8.3f ms, %03d invoc, %s", nanoCosts/1e6, count, name);
98 }
99 }
100 public static void resetForNameCount() {
102 synchronized(forNameLock) {
103 forNameCount=0;
104 forNameNanoCosts=0;
105 forNameStats.clear();
106 }
107 }
108 }
109 public static StringBuilder getForNameStats(StringBuilder sb) {
110 if( null == sb ) {
111 sb = new StringBuilder();
112 }
114 synchronized(forNameLock) {
115 sb.append(String.format("ReflectionUtil.forName: %8.3f ms, %03d invoc%n", forNameNanoCosts/1e6, forNameCount));
116 final Set<Entry<String, ClassNameLookup>> entries = forNameStats.entrySet();
117 int entryNum = 0;
118 for(final Iterator<Entry<String, ClassNameLookup>> iter = entries.iterator(); iter.hasNext(); entryNum++) {
119 final Entry<String, ClassNameLookup> entry = iter.next();
120 sb.append(String.format("ReflectionUtil.forName[%03d]: %s%n", entryNum, entry.getValue()));
121 }
122 }
123 }
124 return sb;
125 }
126
127 private static Class<?> getClassImpl(final String clazzName, final boolean initializeClazz, final ClassLoader cl) throws ClassNotFoundException {
129 final long t0 = Clock.currentNanos();
130 final Class<?> res = Class.forName(clazzName, initializeClazz, cl);
131 final long t1 = Clock.currentNanos();
132 final long nanoCosts = t1 - t0;
133 synchronized(forNameLock) {
134 forNameCount++;
135 forNameNanoCosts += nanoCosts;
136 ClassNameLookup cnl = forNameStats.get(clazzName);
137 if( null == cnl ) {
138 cnl = new ClassNameLookup(clazzName);
139 forNameStats.put(clazzName, cnl);
140 }
141 cnl.count++;
142 cnl.nanoCosts += nanoCosts;
143 System.err.printf("ReflectionUtil.getClassImpl.%03d: %8.3f ms, init %b, [%s]@ Thread %s%n",
144 forNameCount, nanoCosts/1e6, initializeClazz, cnl.toString(), Thread.currentThread().getName());
145 if(DEBUG) {
146 ExceptionUtils.dumpStack(System.err);
147 }
148 }
149 return res;
150 } else {
151 return Class.forName(clazzName, initializeClazz, cl);
152 }
153 }
154
155 /**
156 * Returns true only if the class could be loaded.
157 */
158 public static final boolean isClassAvailable(final String clazzName, final ClassLoader cl) {
159 try {
160 return null != getClassImpl(clazzName, false, cl);
161 } catch (final ClassNotFoundException e) {
162 return false;
163 }
164 }
165
166 /**
167 * Loads and returns the class or null.
168 * @see Class#forName(java.lang.String, boolean, java.lang.ClassLoader)
169 */
170 public static final Class<?> getClass(final String clazzName, final boolean initializeClazz, final ClassLoader cl)
172 try {
173 return getClassImpl(clazzName, initializeClazz, cl);
174 } catch (final ClassNotFoundException e) {
175 throw new JogampRuntimeException(clazzName + " not available", e);
176 }
177 }
178
179 /**
180 * @param initializeClazz TODO
181 * @throws JogampRuntimeException if the constructor can not be delivered.
182 */
183 public static final Constructor<?> getConstructor(final String clazzName, final Class<?>[] cstrArgTypes, final boolean initializeClazz, final ClassLoader cl)
185 try {
186 return getConstructor(getClassImpl(clazzName, initializeClazz, cl), cstrArgTypes);
187 } catch (final ClassNotFoundException ex) {
188 throw new JogampRuntimeException(clazzName + " not available", ex);
189 }
190 }
191
192 static final String asString(final Class<?>[] argTypes) {
193 final StringBuilder args = new StringBuilder();
194 boolean coma = false;
195 if(null != argTypes) {
196 for (int i = 0; i < argTypes.length; i++) {
197 if(coma) {
198 args.append(", ");
199 }
200 args.append(argTypes[i].getName());
201 coma = true;
202 }
203 }
204 return args.toString();
205 }
206
207 /**
208 * Returns a compatible constructor
209 * if available, otherwise throws an exception.
210 * <p>
211 * It first attempts to get the specific Constructor
212 * using the given <code>cstrArgTypes</code>.
213 * If this fails w/ <code>NoSuchMethodException</code>, a compatible
214 * Constructor is being looked-up w/ with parameter types assignable
215 * from the given <code>cstrArgs</code>.
216 * </p>
217 *
218 * @throws JogampRuntimeException if the constructor can not be delivered.
219 */
220 public static final Constructor<?> getConstructor(final Class<?> clazz, Class<?> ... cstrArgTypes)
222 if(null == cstrArgTypes) {
223 cstrArgTypes = zeroTypes;
224 }
225 Constructor<?> cstr = null;
226 try {
227 cstr = clazz.getDeclaredConstructor(cstrArgTypes);
228 } catch (final NoSuchMethodException ex) {
229 // ok, cont. w/ 'isAssignableFrom()' validation
230 }
231 if(null == cstr) {
232 final Constructor<?>[] cstrs = clazz.getConstructors();
233 for(int i=0; null==cstr && i<cstrs.length; i++) {
234 final Constructor<?> c = cstrs[i];
235 final Class<?>[] types = c.getParameterTypes();
236 if(types.length == cstrArgTypes.length) {
237 int j;
238 for(j=0; j<types.length; j++) {
239 if(!types[j].isAssignableFrom(cstrArgTypes[j])) {
240 break; // cont w/ next cstr
241 }
242 }
243 if(types.length == j) {
244 cstr = c; // gotcha
245 }
246 }
247 }
248 }
249 if(null == cstr) {
250 throw new JogampRuntimeException("Constructor: '" + clazz.getName() + "(" + asString(cstrArgTypes) + ")' not found");
251 }
252 return cstr;
253 }
254
255 public static final Constructor<?> getConstructor(final String clazzName, final ClassLoader cl)
257 return getConstructor(clazzName, null, true, cl);
258 }
259
260 /**
261 * @throws JogampRuntimeException if the instance can not be created.
262 */
263 public static final Object createInstance(final Constructor<?> cstr, final Object ... cstrArgs)
264 throws JogampRuntimeException, RuntimeException
265 {
266 try {
267 return cstr.newInstance(cstrArgs);
268 } catch (final Exception e) {
269 Throwable t = e;
270 if (t instanceof InvocationTargetException) {
271 t = ((InvocationTargetException) t).getTargetException();
272 }
273 if (t instanceof Error) {
274 throw (Error) t;
275 }
276 if (t instanceof RuntimeException) {
277 throw (RuntimeException) t;
278 }
279 throw new JogampRuntimeException("can not create instance of "+cstr.getName(), t);
280 }
281 }
282
283 /**
284 * @throws JogampRuntimeException if the instance can not be created.
285 */
286 public static final Object createInstance(final Class<?> clazz, final Class<?>[] cstrArgTypes, final Object ... cstrArgs)
287 throws JogampRuntimeException, RuntimeException
288 {
289 return createInstance(getConstructor(clazz, cstrArgTypes), cstrArgs);
290 }
291
292 public static final Object createInstance(final Class<?> clazz, final Object ... cstrArgs)
293 throws JogampRuntimeException, RuntimeException
294 {
295 Class<?>[] cstrArgTypes = null;
296 if(null!=cstrArgs) {
297 cstrArgTypes = new Class[cstrArgs.length];
298 for(int i=0; i<cstrArgs.length; i++) {
299 cstrArgTypes[i] = cstrArgs[i].getClass();
300 }
301 }
302 return createInstance(clazz, cstrArgTypes, cstrArgs);
303 }
304
305 public static final Object createInstance(final String clazzName, final Class<?>[] cstrArgTypes, final Object[] cstrArgs, final ClassLoader cl)
306 throws JogampRuntimeException, RuntimeException
307 {
308 try {
309 return createInstance(getClassImpl(clazzName, true, cl), cstrArgTypes, cstrArgs);
310 } catch (final ClassNotFoundException ex) {
311 throw new JogampRuntimeException(clazzName + " not available", ex);
312 }
313 }
314
315 public static final Object createInstance(final String clazzName, final Object[] cstrArgs, final ClassLoader cl)
316 throws JogampRuntimeException, RuntimeException
317 {
318 Class<?>[] cstrArgTypes = null;
319 if(null!=cstrArgs) {
320 cstrArgTypes = new Class[cstrArgs.length];
321 for(int i=0; i<cstrArgs.length; i++) {
322 cstrArgTypes[i] = cstrArgs[i].getClass();
323 }
324 }
325 return createInstance(clazzName, cstrArgTypes, cstrArgs, cl);
326 }
327
328 public static final Object createInstance(final String clazzName, final ClassLoader cl)
329 throws JogampRuntimeException, RuntimeException
330 {
331 return createInstance(clazzName, null, null, cl);
332 }
333
334 public static final boolean instanceOf(final Object obj, final String clazzName) {
335 return instanceOf(obj.getClass(), clazzName);
336 }
337 public static final boolean instanceOf(Class<?> clazz, final String clazzName) {
338 do {
339 if(clazz.getName().equals(clazzName)) {
340 return true;
341 }
342 clazz = clazz.getSuperclass();
343 } while (clazz!=null);
344 return false;
345 }
346
347 public static final boolean implementationOf(final Object obj, final String faceName) {
348 return implementationOf(obj.getClass(), faceName);
349 }
350 public static final boolean implementationOf(Class<?> clazz, final String faceName) {
351 do {
352 final Class<?>[] clazzes = clazz.getInterfaces();
353 for(int i=clazzes.length-1; i>=0; i--) {
354 final Class<?> face = clazzes[i];
355 if(face.getName().equals(faceName)) {
356 return true;
357 }
358 }
359 clazz = clazz.getSuperclass();
360 } while (clazz!=null);
361 return false;
362 }
363
364 public static boolean isAWTComponent(final Object target) {
365 return instanceOf(target, AWTNames.ComponentClass);
366 }
367
368 public static boolean isAWTComponent(final Class<?> clazz) {
369 return instanceOf(clazz, AWTNames.ComponentClass);
370 }
371
372 /**
373 * @throws JogampRuntimeException if the Method can not be found.
374 */
375 public static final Method getMethod(final Class<?> clazz, final String methodName, final Class<?> ... argTypes)
376 throws JogampRuntimeException, RuntimeException
377 {
378 Throwable t = null;
379 Method m = null;
380 try {
381 m = clazz.getDeclaredMethod(methodName, argTypes);
382 } catch (final NoClassDefFoundError ex0) {
383 t = ex0;
384 } catch (final NoSuchMethodException ex1) {
385 t = ex1;
386 }
387 if(null != t) {
388 throw new JogampRuntimeException("Method: '" + clazz + "." + methodName + "(" + asString(argTypes) + ")' not found", t);
389 }
390 return m;
391 }
392
393 /**
394 * @throws JogampRuntimeException if the Method can not be found.
395 */
396 public static final Method getMethod(final String clazzName, final String methodName, final Class<?>[] argTypes, final ClassLoader cl)
397 throws JogampRuntimeException, RuntimeException
398 {
399 try {
400 return getMethod(getClassImpl(clazzName, true, cl), methodName, argTypes);
401 } catch (final ClassNotFoundException ex) {
402 throw new JogampRuntimeException(clazzName + " not available", ex);
403 }
404 }
405
406 /**
407 * @param instance may be null in case of a static method
408 * @param method the method to be called
409 * @param args the method arguments
410 * @return the methods result, maybe null if void
411 * @throws JogampRuntimeException if call fails
412 * @throws RuntimeException if call fails
413 */
414 public static final Object callMethod(final Object instance, final Method method, final Object ... args)
415 throws JogampRuntimeException, RuntimeException
416 {
417 try {
418 return method.invoke(instance, args);
419 } catch (final Exception e) {
420 Throwable t = e;
421 if (t instanceof InvocationTargetException) {
422 t = ((InvocationTargetException) t).getTargetException();
423 }
424 if (t instanceof Error) {
425 throw (Error) t;
426 }
427 if (t instanceof RuntimeException) {
428 throw (RuntimeException) t;
429 }
430 throw new JogampRuntimeException("calling "+method+" failed", t);
431 }
432 }
433
434 /**
435 * @throws JogampRuntimeException if the instance can not be created.
436 */
437 public static final Object callStaticMethod(final String clazzName, final String methodName, final Class<?>[] argTypes, final Object[] args, final ClassLoader cl)
438 throws JogampRuntimeException, RuntimeException
439 {
440 return callMethod(null, getMethod(clazzName, methodName, argTypes, cl), args);
441 }
442
443 /** Convenient Method access class */
444 public static class MethodAccessor {
445 Method m = null;
446
447 /** Check {@link #available()} before using instance. */
448 public MethodAccessor(final Class<?> clazz, final String methodName, final Class<?> ... argTypes) {
449 try {
450 m = ReflectionUtil.getMethod(clazz, methodName, argTypes);
451 } catch (final JogampRuntimeException jre) { /* method n/a */ }
452 }
453
454 /** Returns true if method is available, otherwise false. */
455 public boolean available() {
456 return null != m;
457 }
458
459 /**
460 * Check {@link #available()} before calling to avoid throwing a JogampRuntimeException.
461 * @throws JogampRuntimeException if method is not available
462 */
463 public Object callMethod(final Object instance, final Object ... args) {
464 if(null == m) {
465 throw new JogampRuntimeException("Method not available. Instance: "+instance);
466 }
467 return ReflectionUtil.callMethod(instance, m, args);
468 }
469 }
470
471}
472
static void dumpStack(final PrintStream out)
A generic unchecked exception for Jogamp errors used throughout the binding as a substitute for Runti...
static native long currentNanos()
Returns current monotonic nanoseconds since start of this application.
Helper routines for accessing properties.
static final boolean isPropertyDefined(final String property, final boolean jnlpAlias)
Object callMethod(final Object instance, final Object ... args)
Check available() before calling to avoid throwing a JogampRuntimeException.
boolean available()
Returns true if method is available, otherwise false.
MethodAccessor(final Class<?> clazz, final String methodName, final Class<?> ... argTypes)
Check available() before using instance.
static final Method getMethod(final String clazzName, final String methodName, final Class<?>[] argTypes, final ClassLoader cl)
static final Method getMethod(final Class<?> clazz, final String methodName, final Class<?> ... argTypes)
static StringBuilder getForNameStats(StringBuilder sb)
static final Object createInstance(final String clazzName, final Class<?>[] cstrArgTypes, final Object[] cstrArgs, final ClassLoader cl)
static final Object callStaticMethod(final String clazzName, final String methodName, final Class<?>[] argTypes, final Object[] args, final ClassLoader cl)
static final boolean instanceOf(final Object obj, final String clazzName)
static final Object createInstance(final Class<?> clazz, final Object ... cstrArgs)
static final boolean implementationOf(final Object obj, final String faceName)
static final boolean isClassAvailable(final String clazzName, final ClassLoader cl)
Returns true only if the class could be loaded.
static final Object createInstance(final Constructor<?> cstr, final Object ... cstrArgs)
static final Object createInstance(final String clazzName, final ClassLoader cl)
static final Object createInstance(final Class<?> clazz, final Class<?>[] cstrArgTypes, final Object ... cstrArgs)
static final Object createInstance(final String clazzName, final Object[] cstrArgs, final ClassLoader cl)
static final boolean instanceOf(Class<?> clazz, final String clazzName)
static boolean isAWTComponent(final Class<?> clazz)
static final Constructor<?> getConstructor(final String clazzName, final Class<?>[] cstrArgTypes, final boolean initializeClazz, final ClassLoader cl)
static final boolean implementationOf(Class<?> clazz, final String faceName)
static final Class<?> getClass(final String clazzName, final boolean initializeClazz, final ClassLoader cl)
Loads and returns the class or null.
static final Constructor<?> getConstructor(final String clazzName, final ClassLoader cl)
static boolean isAWTComponent(final Object target)
static final Constructor<?> getConstructor(final Class<?> clazz, Class<?> ... cstrArgTypes)
Returns a compatible constructor if available, otherwise throws an exception.
static final Object callMethod(final Object instance, final Method method, final Object ... args)