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&lt;?&gt; 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&lt;Person&gt; 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    }