package com.softwaremill.common.cdi.autofactory.extension;
import org.jboss.weld.Container;
import org.jboss.weld.injection.ConstructorInjectionPoint;
import org.jboss.weld.injection.CurrentInjectionPoint;
import org.jboss.weld.introspector.WeldConstructor;
import com.softwaremill.common.cdi.autofactory.extension.parameter.ParameterValue;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @author Adam Warski (adam at warski dot org)
*/
public class FactoryInvocationHandler<T> implements InvocationHandler {
private final BeanManager beanManager;
private final Bean<T> bean;
private final CreatedTypeData<T> createdTypeData;
private final CreationalContext<T> creationalContext;
public FactoryInvocationHandler(BeanManager beanManager, Bean<T> bean, CreatedTypeData<T> createdTypeData,
CreationalContext<T> creationalContext) {
this.beanManager = beanManager;
this.bean = bean;
this.createdTypeData = createdTypeData;
this.creationalContext = creationalContext;
}
@Override
public Object invoke(Object o, Method method, Object[] parameters) throws Throwable {
T instance;
if (createdTypeData.isConstructorInjection()) {
CurrentInjectionPoint currentInjectionPoint = Container.instance().services().get(CurrentInjectionPoint.class);
currentInjectionPoint.push(ConstructorInjectionPoint.of(bean, (WeldConstructor<T>) createdTypeData.getCreatedTypeConstructor()));
instance = newInstance(parameters);
currentInjectionPoint.pop();
} else {
instance = newInstance(parameters);
createdTypeData.getCreatedTypeInjectionTarget().inject(instance, creationalContext);
createdTypeData.getCreatedTypeInjectionTarget().postConstruct(instance);
}
return instance;
}
private T newInstance(Object[] parameters) throws InstantiationException, IllegalAccessException, InvocationTargetException {
return createdTypeData.getCreatedTypeConstructor().getJavaMember().newInstance(createConstructorParameters(parameters));
}
private Object[] createConstructorParameters(Object[] factoryMethodParameters) {
ParameterValue[] createdTypeConstructorParameterValues = createdTypeData.getCreatedTypeConstructorParameterValues();
Object[] constructorParameters = new Object[createdTypeConstructorParameterValues.length];
for (int i = 0; i < createdTypeConstructorParameterValues.length; i++) {
ParameterValue createdTypeConstructorParameterValue = createdTypeConstructorParameterValues[i];
constructorParameters[i] = createdTypeConstructorParameterValue.getValue(beanManager, factoryMethodParameters);
}
return constructorParameters;
}
}