001 /* 002 * Created on Oct 31, 2006 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with 005 * 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 is distributed on 010 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 011 * specific language governing permissions and limitations under the License. 012 * 013 * Copyright @2006-2009 the original author or authors. 014 */ 015 package org.fest.reflect.constructor; 016 017 import static org.fest.reflect.util.Accessibles.makeAccessible; 018 import static org.fest.reflect.util.Accessibles.setAccessibleIgnoringExceptions; 019 import static org.fest.reflect.util.Throwables.targetOf; 020 import static org.fest.util.Strings.concat; 021 022 import java.lang.reflect.Constructor; 023 import java.util.Arrays; 024 025 import org.fest.reflect.exception.ReflectionError; 026 027 /** 028 * Understands the invocation of a constructor via Java Reflection. 029 * @param <T> the class in which the constructor is declared. 030 * <p> 031 * The following is an example of proper usage of the classes in this package: 032 * <pre> 033 * // Equivalent to call 'new Person()' 034 * Person p = {@link org.fest.reflect.core.Reflection#constructor() constructor}().{@link TargetType#in in}(Person.class).{@link #newInstance newInstance}(); 035 * 036 * // Equivalent to call 'new Person("Yoda")' 037 * Person p = {@link org.fest.reflect.core.Reflection#constructor() constructor}().{@link TargetType#withParameterTypes(Class...) withParameterTypes}(String.class).{@link ParameterTypes#in(Class) in}(Person.class).{@link #newInstance newInstance}("Yoda"); 038 * </pre> 039 * </p> 040 * 041 * @author Alex Ruiz 042 * @author Yvonne Wang 043 */ 044 public final class Invoker<T> { 045 046 public static <T> Invoker<T> newInvoker(Class<T> target, Class<?>... parameterTypes) { 047 Constructor<T> constructor = constructor(target, parameterTypes); 048 return new Invoker<T>(constructor); 049 } 050 051 private static <T> Constructor<T> constructor(Class<T> target, Class<?>... parameterTypes) { 052 try { 053 return target.getDeclaredConstructor(parameterTypes); 054 } catch (Exception e) { 055 throw new ReflectionError(concat("Unable to find constructor in type ", target.getName(), 056 " with parameter types ", Arrays.toString(parameterTypes)), e); 057 } 058 } 059 060 private final Constructor<T> constructor; 061 062 private Invoker(Constructor<T> constructor) { 063 this.constructor = constructor; 064 } 065 066 /** 067 * Creates a new instance of <code>T</code> by calling a constructor with the given arguments. 068 * @param args the arguments to pass to the constructor (can be zero or more). 069 * @return the created instance of <code>T</code>. 070 * @throws ReflectionError if a new instance cannot be created. 071 */ 072 public T newInstance(Object... args) { 073 boolean accessible = constructor.isAccessible(); 074 try { 075 makeAccessible(constructor); 076 T newInstance = constructor.newInstance(args); 077 return newInstance; 078 } catch (Throwable t) { 079 Throwable cause = targetOf(t); 080 if (cause instanceof RuntimeException) throw (RuntimeException)cause; 081 throw new ReflectionError("Unable to create a new object from the enclosed constructor", cause); 082 } finally { 083 setAccessibleIgnoringExceptions(constructor, accessible); 084 } 085 } 086 087 /** 088 * Returns the "real" constructor managed by this class. 089 * @return the "real" constructor managed by this class. 090 */ 091 public Constructor<T> info() { 092 return constructor; 093 } 094 }