001    /**
002     *
003     * Copyright 2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  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.activemq.util;
018    
019    import java.lang.reflect.Array;
020    import java.util.HashMap;
021    import java.util.Map;
022    
023    /**
024     * Utilities for loading classes.
025     * 
026     * @version $Rev: 109957 $ $Date: 2005/03/11 21:14:53 $
027     */
028    public class ClassLoading {
029    
030        /**
031         * Load a class for the given name. <p/>
032         * <p>
033         * Handles loading primitive types as well as VM class and array syntax.
034         * 
035         * @param className
036         *            The name of the Class to be loaded.
037         * @param classLoader
038         *            The class loader to load the Class object from.
039         * @return The Class object for the given name.
040         * @throws ClassNotFoundException
041         *             Failed to load Class object.
042         */
043        public static Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
044            if (className == null) {
045                throw new IllegalArgumentException("className is null");
046            }
047    
048            // First just try to load
049            try {
050                return load(className, classLoader);
051            } catch (ClassNotFoundException ignore) {
052                // handle special cases below
053            }
054    
055            Class type = null;
056    
057            // Check if it is a primitive type
058            type = getPrimitiveType(className);
059            if (type != null)
060                return type;
061    
062            // Check if it is a vm primitive
063            type = getVMPrimitiveType(className);
064            if (type != null)
065                return type;
066    
067            // Handle VM class syntax (Lclassname;)
068            if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
069                String name = className.substring(1, className.length() - 1);
070                return load(name, classLoader);
071            }
072    
073            // Handle VM array syntax ([type)
074            if (className.charAt(0) == '[') {
075                int arrayDimension = className.lastIndexOf('[') + 1;
076                String componentClassName = className.substring(arrayDimension, className.length());
077                type = loadClass(componentClassName, classLoader);
078    
079                int dim[] = new int[arrayDimension];
080                java.util.Arrays.fill(dim, 0);
081                return Array.newInstance(type, dim).getClass();
082            }
083    
084            // Handle user friendly type[] syntax
085            if (className.endsWith("[]")) {
086                // get the base component class name and the arrayDimensions
087                int arrayDimension = 0;
088                String componentClassName = className;
089                while (componentClassName.endsWith("[]")) {
090                    componentClassName = componentClassName.substring(0, componentClassName.length() - 2);
091                    arrayDimension++;
092                }
093    
094                // load the base type
095                type = loadClass(componentClassName, classLoader);
096    
097                // return the array type
098                int[] dim = new int[arrayDimension];
099                java.util.Arrays.fill(dim, 0);
100                return Array.newInstance(type, dim).getClass();
101            }
102    
103            // Else we can not load (give up)
104            throw new ClassNotFoundException(className);
105        }
106    
107        private static Class load(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
108            if (classLoader == null)
109                return Class.forName(className);
110            else
111                return classLoader.loadClass(className);
112        }
113    
114        public static String getClassName(Class clazz) {
115            StringBuffer rc = new StringBuffer();
116            while (clazz.isArray()) {
117                rc.append('[');
118                clazz = clazz.getComponentType();
119            }
120            if (!clazz.isPrimitive()) {
121                rc.append('L');
122                rc.append(clazz.getName());
123                rc.append(';');
124            } else {
125                rc.append(VM_PRIMITIVES_REVERSE.get(clazz));
126            }
127            return rc.toString();
128        }
129    
130        /**
131         * Primitive type name -> class map.
132         */
133        private static final Map PRIMITIVES = new HashMap();
134    
135        /** Setup the primitives map. */
136        static {
137            PRIMITIVES.put("boolean", Boolean.TYPE);
138            PRIMITIVES.put("byte", Byte.TYPE);
139            PRIMITIVES.put("char", Character.TYPE);
140            PRIMITIVES.put("short", Short.TYPE);
141            PRIMITIVES.put("int", Integer.TYPE);
142            PRIMITIVES.put("long", Long.TYPE);
143            PRIMITIVES.put("float", Float.TYPE);
144            PRIMITIVES.put("double", Double.TYPE);
145            PRIMITIVES.put("void", Void.TYPE);
146        }
147    
148        /**
149         * Get the primitive type for the given primitive name.
150         * 
151         * @param name
152         *            Primitive type name (boolean, byte, int, ...)
153         * @return Primitive type or null.
154         */
155        private static Class getPrimitiveType(final String name) {
156            return (Class) PRIMITIVES.get(name);
157        }
158    
159        /**
160         * VM primitive type name -> primitive type
161         */
162        private static final HashMap VM_PRIMITIVES = new HashMap();
163    
164        /** Setup the vm primitives map. */
165        static {
166            VM_PRIMITIVES.put("B", byte.class);
167            VM_PRIMITIVES.put("C", char.class);
168            VM_PRIMITIVES.put("D", double.class);
169            VM_PRIMITIVES.put("F", float.class);
170            VM_PRIMITIVES.put("I", int.class);
171            VM_PRIMITIVES.put("J", long.class);
172            VM_PRIMITIVES.put("S", short.class);
173            VM_PRIMITIVES.put("Z", boolean.class);
174            VM_PRIMITIVES.put("V", void.class);
175        }
176    
177        /**
178         * VM primitive type primitive type -> name
179         */
180        private static final HashMap VM_PRIMITIVES_REVERSE = new HashMap();
181    
182        /** Setup the vm primitives reverse map. */
183        static {
184            VM_PRIMITIVES_REVERSE.put(byte.class, "B");
185            VM_PRIMITIVES_REVERSE.put(char.class, "C");
186            VM_PRIMITIVES_REVERSE.put(double.class, "D");
187            VM_PRIMITIVES_REVERSE.put(float.class, "F");
188            VM_PRIMITIVES_REVERSE.put(int.class, "I");
189            VM_PRIMITIVES_REVERSE.put(long.class, "J");
190            VM_PRIMITIVES_REVERSE.put(short.class, "S");
191            VM_PRIMITIVES_REVERSE.put(boolean.class, "Z");
192            VM_PRIMITIVES_REVERSE.put(void.class, "V");
193        }
194    
195        /**
196         * Get the primitive type for the given VM primitive name. <p/>
197         * <p>
198         * Mapping:
199         * 
200         * <pre>
201         * 
202         *    B - byte
203         *    C - char
204         *    D - double
205         *    F - float
206         *    I - int
207         *    J - long
208         *    S - short
209         *    Z - boolean
210         *    V - void
211         *  
212         * </pre>
213         * 
214         * @param name
215         *            VM primitive type name (B, C, J, ...)
216         * @return Primitive type or null.
217         */
218        private static Class getVMPrimitiveType(final String name) {
219            return (Class) VM_PRIMITIVES.get(name);
220        }
221    
222        /**
223         * Map of primitive types to their wrapper classes
224         */
225        private static final Map PRIMITIVE_WRAPPERS = new HashMap();
226    
227        /** Setup the wrapper map. */
228        static {
229            PRIMITIVE_WRAPPERS.put(Boolean.TYPE, Boolean.class);
230            PRIMITIVE_WRAPPERS.put(Byte.TYPE, Byte.class);
231            PRIMITIVE_WRAPPERS.put(Character.TYPE, Character.class);
232            PRIMITIVE_WRAPPERS.put(Double.TYPE, Double.class);
233            PRIMITIVE_WRAPPERS.put(Float.TYPE, Float.class);
234            PRIMITIVE_WRAPPERS.put(Integer.TYPE, Integer.class);
235            PRIMITIVE_WRAPPERS.put(Long.TYPE, Long.class);
236            PRIMITIVE_WRAPPERS.put(Short.TYPE, Short.class);
237            PRIMITIVE_WRAPPERS.put(Void.TYPE, Void.class);
238        }
239    }