You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by jd...@apache.org on 2003/08/28 11:08:04 UTC

cvs commit: incubator-geronimo/modules/common/src/java/org/apache/geronimo/common Classes.java

jdillon     2003/08/28 02:08:04

  Added:       modules/common/src/test/org/apache/geronimo/common
                        ClassesTest.java
               modules/common/src/java/org/apache/geronimo/common
                        Classes.java
  Log:
   o Common class utilities & some tests
  
  Revision  Changes    Path
  1.1                  incubator-geronimo/modules/common/src/test/org/apache/geronimo/common/ClassesTest.java
  
  Index: ClassesTest.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Geronimo" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Geronimo", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * ====================================================================
   */
  
  package org.apache.geronimo.common;
  
  import junit.framework.TestCase;
  
  /**
   * Unit test for {@link Classes} class.
   *
   * @version $Revision: 1.1 $ $Date: 2003/08/28 09:08:03 $
   */
  public class ClassesTest
      extends TestCase
  {
      protected Class loadClass(final String name)
      {
          Class type = null;
          
          try {
              type = Classes.loadClass(name);
          }
          catch (ClassNotFoundException e) {
              fail("Class should have been found: " + e);
          }
          
          assertNotNull(type);
          
          return type;
      }
      
      public void testLoadClass_Simple()
      {
          String className = "org.apache.geronimo.common.Classes";
          Class type = loadClass(className);
          assertEquals(className, type.getName());
      }
      
      public void testLoadClass_Missing()
      {
          String className = "some.class.that.does.not.Exist";
          try {
              Classes.loadClass(className);
              fail("Expected ClassNotFoundException: " + className);
          }
          catch (ClassNotFoundException ignore) {}
      }
      
      public void testLoadClass_Primitives()
      {
          String className = "boolean";
          Class type = loadClass(className);
          assertEquals(className, type.getName());
      }
      
      public void testLoadClass_VMPrimitives()
      {
          String className = "B";
          Class type = loadClass(className);
          assertEquals(byte.class, type);
      }
      
      public void testLoadClass_VMClassSyntax()
      {
          String className = "org.apache.geronimo.common.Classes";
          Class type = loadClass("L" + className + ";");
          assertEquals(className, type.getName());
      }
      
      public void testLoadClass_VMArraySyntax()
      {
          String className = "[B";
          Class type = loadClass(className);
          assertEquals(byte[].class, type);
      }
  }
  
  
  
  1.1                  incubator-geronimo/modules/common/src/java/org/apache/geronimo/common/Classes.java
  
  Index: Classes.java
  ===================================================================
  /* ====================================================================
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2003 The Apache Software Foundation.  All rights
   * reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution,
   *    if any, must include the following acknowledgment:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowledgment may appear in the software itself,
   *    if and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "Apache" and "Apache Software Foundation" and
   *    "Apache Geronimo" must not be used to endorse or promote products
   *    derived from this software without prior written permission. For
   *    written permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    "Apache Geronimo", nor may "Apache" appear in their name, without
   *    prior written permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   *
   * ====================================================================
   */
  
  package org.apache.geronimo.common;
  
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Array;
  
  import java.util.Map;
  import java.util.HashMap;
  
  import java.io.IOException;
  
  /**
   * A collection of <code>Class</code> utilities.
   *
   * @version $Revision: 1.1 $ $Date: 2003/08/28 09:08:03 $
   */
  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 = "";
      
      /**
       * 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) {
          if (className == null) {
              throw new NullArgumentException("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) {
          if (type == null) {
              throw new NullArgumentException("type");
          }
          
          return stripPackageName(type.getName());
      }
      
      /**
       * Get the package name of the specified class.
       *
       * @param className  Class name.
       * @return           Package name or {@link #DEFAULT_PACKAGE_NAME} if the className is in the
       *                   <i>default</i> package.
       *
       * @throws IllegalArgumentException     className is an empty string.
       */
      public static String getPackageName(final String className) {
          if (className == null) {
              throw new NullArgumentException("className");
          }
          if (className.length() == 0) {
              throw new IllegalArgumentException("className string is empty");
          }
          
          int index = className.lastIndexOf(PACKAGE_SEPARATOR);
          if (index != -1) {
              return className.substring(0, index);
          }
          return DEFAULT_PACKAGE_NAME;
      }
      
      /**
       * Get the package name of the specified class.
       *
       * @param type    Class.
       * @return        Package name.
       */
      public static String getPackageName(final Class type) {
          if (type == null) {
              throw new NullArgumentException("type");
          }
          
          return getPackageName(type.getName());
      }
      
      /**
       * Force the given class to be loaded fully.
       *
       * <p>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 <i>null</i>.
       */
      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);
          assert packageName != null;
          
          if (packageName.startsWith("java.") || 
              packageName.startsWith("javax.")) {
              return;
          }
          
          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, null);
              }
              else {
                  type.newInstance();
              }
          }
          catch (Exception ignore) {
              ThrowableHandler.add(ignore);
          }
      }
  
  
      /////////////////////////////////////////////////////////////////////////
      //                              Primitives                             //
      /////////////////////////////////////////////////////////////////////////
  
      /** Primitive type name -> class map. */
      private static final Map PRIMITIVES = new HashMap();
      
      /** Setup the primitives map. */
      static
      {
          PRIMITIVES.put("boolean", Boolean.TYPE);
          PRIMITIVES.put("byte", Byte.TYPE);
          PRIMITIVES.put("char", Character.TYPE);
          PRIMITIVES.put("short", Short.TYPE);
          PRIMITIVES.put("int", Integer.TYPE);
          PRIMITIVES.put("long", Long.TYPE);
          PRIMITIVES.put("float", Float.TYPE);
          PRIMITIVES.put("double", Double.TYPE);
          PRIMITIVES.put("void", Void.TYPE);
      }
      
      /**
       * Get the primitive type for the given primitive name.
       *
       * @param name    Primitive type name (boolean, byte, int, ...)
       * @return        Primitive type or null.
       */
      public static Class getPrimitiveType(final String name) {
          return (Class)PRIMITIVES.get(name);
      }
      
      /** VM primitive type name -> primitive type */
      private static final HashMap VM_PRIMITIVES = new HashMap();
      
      /** Setup the vm primitives map. */
      static
      {
          VM_PRIMITIVES.put("B", byte.class);
          VM_PRIMITIVES.put("C", char.class);
          VM_PRIMITIVES.put("D", double.class);
          VM_PRIMITIVES.put("F", float.class);
          VM_PRIMITIVES.put("I", int.class);
          VM_PRIMITIVES.put("J", long.class);
          VM_PRIMITIVES.put("S", short.class);
          VM_PRIMITIVES.put("Z", boolean.class);
          VM_PRIMITIVES.put("V", void.class);
      }
      
      /**
       * Get the primitive type for the given VM primitive name.
       *
       * <p>Mapping:
       * <pre>
       *   B - byte
       *   C - char
       *   D - double
       *   F - float
       *   I - int
       *   J - long
       *   S - short
       *   Z - boolean
       *   V - void
       * </pre>
       *
       * @param name    VM primitive type name (B, C, J, ...)
       * @return        Primitive type or null.
       */
      public static Class getVMPrimitiveType(final String name) {
          return (Class)VM_PRIMITIVES.get(name);
      }
      
      /** Map of primitive types to their wrapper classes */
      private static final Map PRIMITIVE_WRAPPERS = new HashMap();
      
      /** Setup the wrapper map. */
      static
      {
          PRIMITIVE_WRAPPERS.put(Boolean.TYPE, Boolean.class);
          PRIMITIVE_WRAPPERS.put(Byte.TYPE, Byte.class);
          PRIMITIVE_WRAPPERS.put(Character.TYPE, Character.class);
          PRIMITIVE_WRAPPERS.put(Double.TYPE, Double.class);
          PRIMITIVE_WRAPPERS.put(Float.TYPE, Float.class);
          PRIMITIVE_WRAPPERS.put(Integer.TYPE, Integer.class);
          PRIMITIVE_WRAPPERS.put(Long.TYPE, Long.class);
          PRIMITIVE_WRAPPERS.put(Short.TYPE, Short.class);
          PRIMITIVE_WRAPPERS.put(Void.TYPE, Void.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 == null) {
              throw new NullArgumentException("type");
          }
          if (! type.isPrimitive()) {
              throw new IllegalArgumentException("type is not a primitive class");
          }
          
          Class wtype = (Class)PRIMITIVE_WRAPPERS.get(type);
          
          // If wrapper type is null then the map is not valid & should be updated
          assert wtype != null;
          
          return wtype;
      }
      
      /**
       * 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) {
          if (type == null) {
              throw new NullArgumentException("type");
          }
          
          return PRIMITIVE_WRAPPERS.containsKey(type);
      }
      
      /**
       * 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 == null) {
              throw new NullArgumentException("type");
          }
          if (type.isPrimitive() || isPrimitiveWrapper(type)) {
              return true;
          }
          
          return false;
      }
      
      
      /////////////////////////////////////////////////////////////////////////
      //                            Class Loading                            //
      /////////////////////////////////////////////////////////////////////////
  
      /**
       * This method acts equivalently to invoking 
       * <code>Thread.currentThread().getContextClassLoader()</code>.
       *
       * @return The thread context class Loader.
       */
      public static ClassLoader getContextClassLoader() {
          return Thread.currentThread().getContextClassLoader();
      }
  
      /**
       * Load a class for the given name using the context class loader.
       *
       * @see #loadClass(String,ClassLoader)
       *
       * @param className    The name of the Class to be loaded.
       * @return             The Class object for the given name.
       *
       * @throws ClassNotFoundException   Failed to load Class object.
       */
      public static Class loadClass(final String className) throws ClassNotFoundException {
          return loadClass(className, getContextClassLoader());
      }
      
      /**
       * Load a class for the given name.
       *
       * <p>Handles loading primitive types as well as VM class and array syntax.
       *
       * @param className     The name of the Class to be loaded.
       * @param classLoader   The class loader to load the Class object from.
       * @return              The Class object for the given name.
       *
       * @throws ClassNotFoundException   Failed to load Class object.
       */
      public static Class loadClass(final String className, final ClassLoader classLoader)
          throws ClassNotFoundException
      {
          if (className == null) {
              throw new NullArgumentException("className");
          }
          if (classLoader == null) {
              throw new NullArgumentException("classLoader");
          }
          
          // First just try to load
          try {
              return classLoader.loadClass(className);
          }
          catch (ClassNotFoundException ignore) {
              // handle special cases below
          }
          
          Class type = null;
          
          // Check if it is a primitive type
          type = getPrimitiveType(className);
          if (type != null) return type;
              
          // Check if it is a vm primitive
          type = getVMPrimitiveType(className);
          if (type != null) return type;
          
          // Handle VM class syntax (Lclassname;)
          if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
              return classLoader.loadClass(className.substring(1, className.length() - 1));
          }
  
          // Handle VM array syntax ([type)
          if (className.charAt(0) == '[') {
              int arrayDimension = className.lastIndexOf('[') + 1;
              String componentClassName = className.substring(arrayDimension, className.length());
              type = loadClass(componentClassName, classLoader);
              
              int dim[] = new int[arrayDimension];
              java.util.Arrays.fill(dim, 0);
              return Array.newInstance(type, dim).getClass();
          }
          
          // Else we can not load (give up)
          throw new ClassNotFoundException(className);
      }
  }