001 /*
002 * Created on Jan 28, 2009
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005 * in compliance with the License. You may obtain a copy of the License at
006 *
007 * http://www.apache.org/licenses/LICENSE-2.0
008 *
009 * Unless required by applicable law or agreed to in writing, software distributed under the License
010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011 * or implied. See the License for the specific language governing permissions and limitations under
012 * the License.
013 *
014 * Copyright @2009 the original author or authors.
015 */
016 package org.fest.reflect.type;
017
018 import org.fest.reflect.exception.ReflectionError;
019
020 import static org.fest.util.Strings.quote;
021
022 /**
023 * Understands loading a class dynamically using a specific <code>{@link ClassLoader}</code>.
024 *
025 * @author Alex Ruiz
026 *
027 * @since 1.1
028 */
029 public final class TypeLoader {
030
031 static TypeLoader newLoader(String name, ClassLoader classLoader) {
032 if (classLoader == null) throw new NullPointerException("The given class loader should not be null");
033 return new TypeLoader(name, classLoader);
034 }
035
036 private final String name;
037 private final ClassLoader classLoader;
038
039 private TypeLoader(String name, ClassLoader classLoader) {
040 this.name = name;
041 this.classLoader = classLoader;
042 }
043
044 /**
045 * Loads the class with the name specified in this type, using this class' <code>ClassLoader</code>.
046 * <p>
047 * Example:
048 * <pre>
049 * Class<?> type = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#withClassLoader(ClassLoader) withClassLoader}(myClassLoader).{@link TypeLoader#load() load}();
050 * </pre>
051 * </p>
052 * @return the loaded class.
053 * @throws ReflectionError wrapping any error that occurred during class loading.
054 */
055 public Class<?> load() {
056 try {
057 return loadType();
058 } catch (Exception e) {
059 throw new ReflectionError(unableToLoadClassMessage(null), e);
060 }
061 }
062
063 /**
064 * Loads the class with the name specified in this type, as the given type, using this class'
065 * <code>ClassLoader</code>.
066 * <p>
067 * The following example shows how to use this method. Let's assume that we have the class <code>Jedi</code> that
068 * extends the class <code>Person</code>:
069 * <pre>
070 * Class<Person> type = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#withClassLoader(ClassLoader) withClassLoader}(myClassLoader).{@link TypeLoader#loadAs(Class) loadAs}(Person.class);
071 * </pre>
072 * </p>
073 * @param type the given type.
074 * @param <T> the generic type of the type.
075 * @return the loaded class.
076 * @throws NullPointerException if the given type is <code>null</code>.
077 * @throws ReflectionError wrapping any error that occurred during class loading.
078 */
079 public <T> Class<? extends T> loadAs(Class<T> type) {
080 if (type == null) throw new NullPointerException("The given type should not be null");
081 try {
082 return loadType().asSubclass(type);
083 } catch (Exception e) {
084 throw new ReflectionError(unableToLoadClassMessage(type), e);
085 }
086 }
087
088 private String unableToLoadClassMessage(Class<?> asType) {
089 StringBuilder msg = new StringBuilder();
090 msg.append("Unable to load class ").append(quote(name));
091 if (asType != null) msg.append(" as ").append(asType.getName());
092 msg.append(" using class loader ").append(classLoader);
093 return msg.toString();
094 }
095
096 private Class<?> loadType() throws ClassNotFoundException {
097 return classLoader.loadClass(name);
098 }
099 }