/*************************************************************************** * Copyright 2009-2012 by Christian Ihle * * kontakt@usikkert.net * * * * This file is part of KouInject. * * * * KouInject is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version. * * * * KouInject is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with KouInject. * * If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ package net.usikkert.kouinject.factory; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collections; import java.util.List; import net.usikkert.kouinject.beandata.BeanKey; import org.apache.commons.lang.Validate; /** * An implementation of {@link FactoryPoint} for representing factory methods. * * @author Christian Ihle * @param <T> The type of class this factory point can create instances of. */ public class FactoryPointMethod<T> implements FactoryPoint<T> { private final Method method; private final BeanKey factoryKey; private final BeanKey returnType; private final List<BeanKey> parameters; private final boolean singleton; /** * Creates a new instance with all the requirements for invoking a factory method. * * @param method The factory method. * @param factoryKey The key to the actual factory bean containing this method. * @param returnType The return type of this factory method. * @param parameters The required parameters for the method to be invoked. * @param singleton If the bean created by this factory method should be a singleton. */ public FactoryPointMethod(final Method method, final BeanKey factoryKey, final BeanKey returnType, final List<BeanKey> parameters, final boolean singleton) { Validate.notNull(method, "Method can not be null"); Validate.notNull(factoryKey, "Factory key can not be null"); Validate.notNull(returnType, "Return type can not be null"); Validate.notNull(parameters, "Parameters can not be null"); this.method = method; this.factoryKey = factoryKey; this.returnType = returnType; this.parameters = Collections.unmodifiableList(parameters); this.singleton = singleton; } /** * {@inheritDoc} */ @Override public BeanKey getFactoryKey() { return factoryKey; } /** * {@inheritDoc} */ @Override public T create(final Object factoryInstance, final Object... factoryPointParameters) { Validate.notNull(factoryInstance, "Factory instance can not be null"); Validate.notNull(factoryPointParameters, "Factory point parameters can not be null"); for (final Object parameter : factoryPointParameters) { Validate.notNull(parameter, "Parameter can not be null"); } final boolean originalAccessible = method.isAccessible(); setAccessible(true); try { final T returnValue = (T) method.invoke(factoryInstance, factoryPointParameters); if (returnValue == null) { throw new UnsupportedOperationException("Factory method returned null: " + method); } return returnValue; } catch (final IllegalAccessException e) { throw new RuntimeException(e); } catch (final InvocationTargetException e) { throw new RuntimeException(e); } finally { setAccessible(originalAccessible); } } private void setAccessible(final boolean accessible) { AccessController.doPrivileged(new PrivilegedAction<Object>() { @Override public Object run() { // Requires java.lang.reflect.ReflectPermission "suppressAccessChecks" method.setAccessible(accessible); return null; } }); } /** * {@inheritDoc} */ @Override public List<BeanKey> getParameters() { return parameters; } /** * {@inheritDoc} */ @Override public BeanKey getReturnType() { return returnType; } /** * {@inheritDoc} */ @Override public boolean isSingleton() { return singleton; } /** * Gets the actual reflection method this factory method will use to create beans. * * @return The reflection method. */ public Method getMethod() { return method; } @Override public String toString() { return "[factory point method] " + method.toGenericString() + " - " + parameters; } }