All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.util.Classes Maven / Gradle / Ivy

There is a newer version: 2.5.0.Final
Show newest version
/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.util;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Array;
import java.lang.NoSuchMethodException;
import java.net.URL;

import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.*;

/**
 * A collection of Class utilities.
 *
 * @version $Revision: 2787 $
 * @author  Jason Dillon
 * @author  Scott Stark
 * @author  Dimitris Andreadis
 */
@SuppressWarnings("unchecked")
public final class Classes
{
   /** The string used to separator packages */
   public static final String PACKAGE_SEPARATOR = ".";

   /** The characther used to separator packages */
   public static final char PACKAGE_SEPARATOR_CHAR = '.';

   /** The default package name. */
   public static final String DEFAULT_PACKAGE_NAME = "";

   /** Format a string buffer containing the Class, Interfaces, CodeSource,
    and ClassLoader information for the given object clazz.

    @param clazz the Class
    @param results - the buffer to write the info to
    */
   public static void displayClassInfo(Class clazz, StringBuffer results)
   {
      // Print out some codebase info for the clazz
      ClassLoader cl = clazz.getClassLoader();
      results.append("\n");
      results.append(clazz.getName());
      results.append("(");
      results.append(Integer.toHexString(clazz.hashCode()));
      results.append(").ClassLoader=");
      results.append(cl);
      ClassLoader parent = cl;
      while( parent != null )
      {
         results.append("\n..");
         results.append(parent);
         URL[] urls = getClassLoaderURLs(parent);
         int length = urls != null ? urls.length : 0;
         for(int u = 0; u < length; u ++)
         {
            results.append("\n....");
            results.append(urls[u]);
         }
         if( parent != null )
            parent = parent.getParent();
      }
      CodeSource clazzCS = clazz.getProtectionDomain().getCodeSource();
      if( clazzCS != null )
      {
         results.append("\n++++CodeSource: ");
         results.append(clazzCS);
      }
      else
         results.append("\n++++Null CodeSource");

      results.append("\nImplemented Interfaces:");
      Class[] ifaces = clazz.getInterfaces();
      for(int i = 0; i < ifaces.length; i ++)
      {
         Class iface = ifaces[i];
         results.append("\n++");
         results.append(iface);
         results.append("(");
         results.append(Integer.toHexString(iface.hashCode()));
         results.append(")");
         ClassLoader loader = ifaces[i].getClassLoader();
         results.append("\n++++ClassLoader: ");
         results.append(loader);
         ProtectionDomain pd = ifaces[i].getProtectionDomain();
         CodeSource cs = pd.getCodeSource();
         if( cs != null )
         {
            results.append("\n++++CodeSource: ");
            results.append(cs);
         }
         else
            results.append("\n++++Null CodeSource");
      }
   }

   /** Use reflection to access a URL[] getURLs or URL[] getClasspath method so
    that non-URLClassLoader class loaders, or class loaders that override
    getURLs to return null or empty, can provide the true classpath info.
    * @param cl 
    * @return the urls
    */
   public static URL[] getClassLoaderURLs(ClassLoader cl)
   {
      URL[] urls = {};
      try
      {
         Class returnType = urls.getClass();
         Class[] parameterTypes = {};
         Class clClass = cl.getClass();
         Method getURLs = clClass.getMethod("getURLs", parameterTypes);
         if( returnType.isAssignableFrom(getURLs.getReturnType()) )
         {
            Object[] args = {};
            urls = (URL[]) getURLs.invoke(cl, args);
         }
         if( urls == null || urls.length == 0 )
         {
            Method getCp = clClass.getMethod("getClasspath", parameterTypes);
            if( returnType.isAssignableFrom(getCp.getReturnType()) )
            {
               Object[] args = {};
               urls = (URL[]) getCp.invoke(cl, args);
            }
         }
      }
      catch(Exception ignore)
      {
      }
      return urls;
   }

   /**
    * Describe the class of an object
    *
    * @param object the object
    * @return the description
    */
   public static String getDescription(Object object)
   {
      StringBuffer buffer = new StringBuffer();
      describe(buffer, object);
      return buffer.toString();
   }

   /**
    * Describe the class of an object
    *
    * @param buffer the string buffer 
    * @param object the object
    */
   public static void describe(StringBuffer buffer, Object object)
   {
      if (object == null)
         buffer.append("**null**");
      else
         describe(buffer, object.getClass());
   }

   /**
    * Describe the class
    *
    * @param buffer the string buffer 
    * @param clazz the clazz
    */
   public static void describe(StringBuffer buffer, Class clazz)
   {
      if (clazz == null)
         buffer.append("**null**");
      else
      {
         buffer.append("{class=").append(clazz.getName());
         Class[] intfs = clazz.getInterfaces();
         if (intfs.length > 0)
         {
            buffer.append(" intfs=");
            for (int i = 0; i < intfs.length; ++i)
            {
               buffer.append(intfs[i].getName());
               if (i < intfs.length-1)
                  buffer.append(", ");
            }
         }
         buffer.append("}");
      }
   }

   /**
    * Get the short name of the specified class by striping off the package
    * name.
    *
    * @param classname  Class name.
    * @return           Short class name.
    */
   public static String stripPackageName(final String classname)
   {
      int idx = classname.lastIndexOf(PACKAGE_SEPARATOR);

      if (idx != -1)
         return classname.substring(idx + 1, classname.length());
      return classname;
   }

   /**
    * Get the short name of the specified class by striping off the package
    * name.
    *
    * @param type    Class name.
    * @return        Short class name.
    */
   public static String stripPackageName(final Class type)
   {
      return stripPackageName(type.getName());
   }

   /**
    * Get the package name of the specified class.
    *
    * @param classname  Class name.
    * @return           Package name or "" if the classname is in the
    *                   default package.
    *
    * @throws EmptyStringException     Classname is an empty string.
    */
   public static String getPackageName(final String classname)
   {
      if (classname.length() == 0)
         throw new EmptyStringException();

      int index = classname.lastIndexOf(PACKAGE_SEPARATOR);
      if (index != -1)
         return classname.substring(0, index);
      return "";
   }

   /**
    * Get the package name of the specified class.
    *
    * @param type    Class.
    * @return        Package name.
    */
   public static String getPackageName(final Class type)
   {
      return getPackageName(type.getName());
   }

   /**
    * Force the given class to be loaded fully.
    *
    * 

This method attempts to locate a static method on the given class * the attempts to invoke it with dummy arguments in the hope that * the virtual machine will prepare the class for the method call and * call all of the static class initializers. * * @param type Class to force load. * * @throws NullArgumentException Type is null. */ public static void forceLoad(final Class type) { if (type == null) throw new NullArgumentException("type"); // don't attempt to force primitives to load if (type.isPrimitive()) return; // don't attempt to force java.* classes to load String packageName = Classes.getPackageName(type); // System.out.println("package name: " + packageName); if (packageName.startsWith("java.") || packageName.startsWith("javax.")) { return; } // System.out.println("forcing class to load: " + type); try { Method methods[] = type.getDeclaredMethods(); Method method = null; for (int i = 0; i < methods.length; i++) { int modifiers = methods[i].getModifiers(); if (Modifier.isStatic(modifiers)) { method = methods[i]; break; } } if (method != null) { method.invoke(null, (Object[]) null); } else { type.newInstance(); } } catch (Exception ignore) { ThrowableHandler.add(ignore); } } ///////////////////////////////////////////////////////////////////////// // Primitives // ///////////////////////////////////////////////////////////////////////// /** Primitive type name -> class map. */ private static final Map PRIMITIVE_NAME_TYPE_MAP = new HashMap(); /** Setup the primitives map. */ static { PRIMITIVE_NAME_TYPE_MAP.put("boolean", Boolean.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("byte", Byte.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("char", Character.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("short", Short.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("int", Integer.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("long", Long.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("float", Float.TYPE); PRIMITIVE_NAME_TYPE_MAP.put("double", Double.TYPE); } /** * Get the primitive type for the given primitive name. * *

* For example, "boolean" returns Boolean.TYPE and so on... * * @param name Primitive type name (boolean, int, byte, ...) * @return Primitive type or null. * * @exception IllegalArgumentException Type is not a primitive class */ public static Class getPrimitiveTypeForName(final String name) { return (Class) PRIMITIVE_NAME_TYPE_MAP.get(name); } /** Map of primitive types to their wrapper classes */ private static final Class[] PRIMITIVE_WRAPPER_MAP = { Boolean.TYPE, Boolean.class, Byte.TYPE, Byte.class, Character.TYPE, Character.class, Double.TYPE, Double.class, Float.TYPE, Float.class, Integer.TYPE, Integer.class, Long.TYPE, Long.class, Short.TYPE, Short.class, }; /** * Get the wrapper class for the given primitive type. * * @param type Primitive class. * @return Wrapper class for primitive. * * @exception IllegalArgumentException Type is not a primitive class */ public static Class getPrimitiveWrapper(final Class type) { if (!type.isPrimitive()) { throw new IllegalArgumentException("type is not a primitive class"); } for (int i = 0; i < PRIMITIVE_WRAPPER_MAP.length; i += 2) { if (type.equals(PRIMITIVE_WRAPPER_MAP[i])) return PRIMITIVE_WRAPPER_MAP[i + 1]; } // should never get here, if we do then PRIMITIVE_WRAPPER_MAP // needs to be updated to include the missing mapping throw new UnreachableStatementException(); } /** * Populates a list with all the interfaces implemented by the argument * class c and all its superclasses. * * @param allIfaces - the list to populate with the interfaces * @param c - the class to start scanning for interfaces */ public static void getAllInterfaces(List allIfaces, Class c) { while (c != null) { Class[] ifaces = c.getInterfaces(); for (int n = 0; n < ifaces.length; n ++) { allIfaces.add(ifaces[n]); } c = c.getSuperclass(); } } /** * Returns an array containing all the unique interfaces implemented * by the argument class c and all its superclasses. Interfaces that * appear multiple times through inheritence are only accounted for once. * * @param c - the class to start scanning for interfaces * @return the interfaces */ public static Class[] getAllUniqueInterfaces(Class c) { Set uniqueIfaces = new HashSet(); while (c != null ) { Class[] ifaces = c.getInterfaces(); for (int n = 0; n < ifaces.length; n ++) { uniqueIfaces.add(ifaces[n]); } c = c.getSuperclass(); } return (Class[])uniqueIfaces.toArray(new Class[uniqueIfaces.size()]); } /** * Check if the given class is a primitive wrapper class. * * @param type Class to check. * @return True if the class is a primitive wrapper. */ public static boolean isPrimitiveWrapper(final Class type) { for (int i = 0; i < PRIMITIVE_WRAPPER_MAP.length; i += 2) { if (type.equals(PRIMITIVE_WRAPPER_MAP[i + 1])) { return true; } } return false; } /** * Check if the given class is a primitive class or a primitive * wrapper class. * * @param type Class to check. * @return True if the class is a primitive or primitive wrapper. */ public static boolean isPrimitive(final Class type) { if (type.isPrimitive() || isPrimitiveWrapper(type)) { return true; } return false; } /** Check type against boolean, byte, char, short, int, long, float, double. * @param type The java type name * @return true if this is a primative type name. */ public static boolean isPrimitive(final String type) { return PRIMITIVE_NAME_TYPE_MAP.containsKey(type); } /** * @param wrapper a primitive wrapper type * @return primitive type the passed in wrapper type corresponds to */ public static Class getPrimitive(Class wrapper) { Class primitive; if(Integer.class == wrapper) { primitive = int.class; } else if(Long.class == wrapper) { primitive = long.class; } else if(Double.class == wrapper) { primitive = double.class; } else if(Boolean.class == wrapper) { primitive = boolean.class; } else if(Short.class == wrapper) { primitive = short.class; } else if(Float.class == wrapper) { primitive = float.class; } else if(Byte.class == wrapper) { primitive = byte.class; } else if(Character.class == wrapper) { primitive = char.class; } else { throw new IllegalArgumentException("The class is not a primitive wrapper type: " + wrapper); } return primitive; } /** * Instantiate a java class object * * @param expected the expected class type * @param property the system property defining the class * @param defaultClassName the default class name * @return the instantiated object */ public static Object instantiate(Class expected, String property, String defaultClassName) { String className = getProperty(property, defaultClassName); Class clazz = null; try { clazz = loadClass(className); } catch (ClassNotFoundException e) { throw new NestedRuntimeException("Cannot load class " + className, e); } Object result = null; try { result = clazz.newInstance(); } catch (InstantiationException e) { throw new NestedRuntimeException("Error instantiating " + className, e); } catch (IllegalAccessException e) { throw new NestedRuntimeException("Error instantiating " + className, e); } if (expected.isAssignableFrom(clazz) == false) throw new NestedRuntimeException("Class " + className + " from classloader " + clazz.getClassLoader() + " is not of the expected class " + expected + " loaded from " + expected.getClassLoader()); return result; } ///////////////////////////////////////////////////////////////////////// // Class Loading // ///////////////////////////////////////////////////////////////////////// /** * This method acts equivalently to invoking * Thread.currentThread().getContextClassLoader().loadClass(className); but it also * supports primitive types and array classes of object types or primitive types. * * @param className the qualified name of the class or the name of primitive type or * array in the same format as returned by the * java.lang.Class.getName() method. * @return the Class object for the requested className * * @throws ClassNotFoundException when the classLoader can not find the requested class */ public static Class loadClass(String className) throws ClassNotFoundException { return loadClass(className, Thread.currentThread().getContextClassLoader()); } /** * This method acts equivalently to invoking classLoader.loadClass(className) * but it also supports primitive types and array classes of object types or * primitive types. * * @param className the qualified name of the class or the name of primitive * type or array in the same format as returned by the * java.lang.Class.getName() method. * @param classLoader the ClassLoader used to load classes * @return the Class object for the requested className * * @throws ClassNotFoundException when the classLoader can not * find the requested class */ public static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { // ClassLoader.loadClass() does not handle primitive types: // // B byte // C char // D double // F float // I int // J long // S short // Z boolean // V void // if (className.length() == 1) { char type = className.charAt(0); if (type == 'B') return Byte.TYPE; if (type == 'C') return Character.TYPE; if (type == 'D') return Double.TYPE; if (type == 'F') return Float.TYPE; if (type == 'I') return Integer.TYPE; if (type == 'J') return Long.TYPE; if (type == 'S') return Short.TYPE; if (type == 'Z') return Boolean.TYPE; if (type == 'V') return Void.TYPE; // else throw... throw new ClassNotFoundException(className); } // Check for a primative type if( isPrimitive(className) == true ) return (Class) Classes.PRIMITIVE_NAME_TYPE_MAP.get(className); // Check for the internal vm format: Lclassname; if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') return classLoader.loadClass(className.substring(1, className.length() - 1)); // first try - be optimistic // this will succeed for all non-array classes and array classes that have already been resolved // try { return classLoader.loadClass(className); } catch (ClassNotFoundException e) { // if it was non-array class then throw it if (className.charAt(0) != '[') throw e; } // we are now resolving array class for the first time // count opening braces int arrayDimension = 0; while (className.charAt(arrayDimension) == '[') arrayDimension++; // resolve component type - use recursion so that we can resolve primitive types also Class componentType = loadClass(className.substring(arrayDimension), classLoader); // construct array class return Array.newInstance(componentType, new int[arrayDimension]).getClass(); } /** * Convert a list of Strings from an Interator into an array of * Classes (the Strings are taken as classnames). * * @param it A java.util.Iterator pointing to a Collection of Strings * @param cl The ClassLoader to use * * @return Array of Classes * * @throws ClassNotFoundException When a class could not be loaded from * the specified ClassLoader */ public final static Class[] convertToJavaClasses(Iterator it, ClassLoader cl) throws ClassNotFoundException { ArrayList> classes = new ArrayList>(); while (it.hasNext()) { classes.add(convertToJavaClass(it.next(), cl)); } return classes.toArray(new Class[classes.size()]); } /** * Returns attribute's getter method. If the method not found then NoSuchMethodException will be thrown. * @param cls the class the attribute belongs too * @param attr the attribute's name * @return attribute's getter method * @throws NoSuchMethodException if the getter was not found */ public final static Method getAttributeGetter(Class cls, String attr) throws NoSuchMethodException { StringBuffer buf = new StringBuffer(attr.length() + 3); buf.append("get"); if(Character.isLowerCase(attr.charAt(0))) { buf.append(Character.toUpperCase(attr.charAt(0))) .append(attr.substring(1)); } else { buf.append(attr); } try { return cls.getMethod(buf.toString(), (Class[]) null); } catch (NoSuchMethodException e) { buf.replace(0, 3, "is"); return cls.getMethod(buf.toString(), (Class[]) null); } } /** * Returns attribute's setter method. If the method not found then NoSuchMethodException will be thrown. * @param cls the class the attribute belongs to * @param attr the attribute's name * @param type the attribute's type * @return attribute's setter method * @throws NoSuchMethodException if the setter was not found */ public final static Method getAttributeSetter(Class cls, String attr, Class type) throws NoSuchMethodException { StringBuffer buf = new StringBuffer(attr.length() + 3); buf.append("set"); if(Character.isLowerCase(attr.charAt(0))) { buf.append(Character.toUpperCase(attr.charAt(0))) .append(attr.substring(1)); } else { buf.append(attr); } return cls.getMethod(buf.toString(), new Class[]{type}); } /** * Convert a given String into the appropriate Class. * * @param name Name of class * @param cl ClassLoader to use * * @return The class for the given name * * @throws ClassNotFoundException When the class could not be found by * the specified ClassLoader */ private final static Class convertToJavaClass(String name, ClassLoader cl) throws ClassNotFoundException { int arraySize = 0; while (name.endsWith("[]")) { name = name.substring(0, name.length() - 2); arraySize++; } // Check for a primitive type Class c = (Class) PRIMITIVE_NAME_TYPE_MAP.get(name); if (c == null) { // No primitive, try to load it from the given ClassLoader try { c = cl.loadClass(name); } catch (ClassNotFoundException cnfe) { throw new ClassNotFoundException("Parameter class not found: " + name); } } // if we have an array get the array class if (arraySize > 0) { int[] dims = new int[arraySize]; for (int i = 0; i < arraySize; i++) { dims[i] = 1; } c = Array.newInstance(c, dims).getClass(); } return c; } /** * Get a system property * * @param name the property name * @param defaultValue the default value */ private static String getProperty(final String name, final String defaultValue) { return (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { return System.getProperty(name, defaultValue); } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy