001    /*
002     * Created on Jan 23, 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.reflect.type.TypeLoader.newLoader;
021    import static org.fest.util.Strings.isEmpty;
022    
023    /**
024     * Understands loading a class dynamically.
025     * <p>
026     * The following is an example of proper usage of this class:
027     * <pre>
028     *   // Loads the class 'org.republic.Jedi'
029     *   Class&lt;?&gt; jediType = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#load() load}();
030     *
031     *   // Loads the class 'org.republic.Jedi' as 'org.republic.Person' (Jedi extends Person)
032     *   Class&lt;Person&gt; jediType = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#loadAs(Class) loadAs}(Person.class);
033     *
034     *   // Loads the class 'org.republic.Jedi' using a custom class loader
035     *   Class&lt;?&gt; jediType = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#withClassLoader(ClassLoader) withClassLoader}(myClassLoader).{@link org.fest.reflect.type.TypeLoader#load() load}();
036     * </pre>
037     * </p>
038     *
039     * @author Alex Ruiz
040     *
041     * @since 1.1
042     */
043    public final class Type {
044    
045      /**
046       * Creates a new <code>{@link Type}</code>: the starting point of the fluent interface for loading classes
047       * dynamically.
048       * @param name the name of the class to load.
049       * @return the created <code>Type</code>.
050       * @throws NullPointerException if the given name is <code>null</code>.
051       * @throws IllegalArgumentException if the given name is empty.
052       */
053      public static Type newType(String name) {
054        if (name == null)
055          throw new NullPointerException("The name of the class to load should not be null");
056        if (isEmpty(name))
057          throw new IllegalArgumentException("The name of the class to load should not be empty");
058        return new Type(name);
059      }
060    
061      private final String name;
062    
063      private Type(String name) {
064        this.name = name;
065      }
066    
067      /**
068       * Loads the class with the name specified in this type, using this class' <code>ClassLoader</code>.
069       * @return the loaded class.
070       * @throws ReflectionError wrapping any error that occurred during class loading.
071       */
072      public Class<?> load() {
073        return newLoader(name, thisClassLoader()).load();
074      }
075    
076      /**
077       * Loads the class with the name specified in this type, as the given type, using this class'
078       * <code>ClassLoader</code>.
079       * <p>
080       * The following example shows how to use this method. Let's assume that we have the class <code>Jedi</code> that
081       * extends the class <code>Person</code>:
082       * <pre>
083       * Class&lt;Person&gt; type = {@link org.fest.reflect.core.Reflection#type(String) type}("org.republic.Jedi").{@link Type#loadAs(Class) loadAs}(Person.class);
084       * </pre>
085       * </p>
086       * @param type the given type.
087       * @param <T> the generic type of the type.
088       * @return the loaded class.
089       * @throws NullPointerException if the given type is <code>null</code>.
090       * @throws ReflectionError wrapping any error that occurred during class loading.
091       */
092      public <T> Class<? extends T> loadAs(Class<T> type) {
093        return newLoader(name, thisClassLoader()).loadAs(type);
094      }
095    
096      private ClassLoader thisClassLoader() { return getClass().getClassLoader(); }
097    
098      /**
099       * Specifies the <code>{@link ClassLoader}</code> to use to load the class.
100       * <p>
101       * Example:
102       * <pre>
103       * 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}();
104       * </pre>
105       * </p>
106       * @param classLoader the given <code>ClassLoader</code>.
107       * @return an object responsible of loading a class with the given <code>ClassLoader</code>.
108       * @throws NullPointerException if the given <code>ClassLoader</code> is <code>null</code>.
109       */
110      public TypeLoader withClassLoader(ClassLoader classLoader) {
111        return newLoader(name, classLoader);
112      }
113    }