package tc.oc.commons.core.inject;
import java.lang.reflect.Constructor;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import com.google.inject.MembersInjector;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import tc.oc.commons.core.util.ExceptionUtils;
/**
* A generic factory that creates {@link T} instances in the same way as an Injector,
* but does not require any binding for {@link T} itself.
*
* The injectable constructor is used to instantiate the class, but none of the
* parameters are injected, they must all be passed to {@link #newInstance(Object...)}.
* However, fields and instance methods *are* injected, and dependencies for those
* injection points are statically propagated to this class.
*/
public class MemberInjectingFactory<T> implements HasDependencies {
protected final TypeLiteral<T> type;
protected final InjectionPoint injectionPoint;
protected final Set<Dependency<?>> dependencies = new HashSet<>();
private final Constructor<T> constructor;
private final MembersInjector<T> injector;
@Inject public MemberInjectingFactory(TypeLiteral<T> type, MembersInjector<T> injector) {
this.type = type;
this.injector = injector;
this.injectionPoint = InjectionPoint.forConstructorOf(type);
this.constructor = (Constructor<T>) injectionPoint.getMember();
this.constructor.setAccessible(true);
dependencies.addAll(Dependency.forInjectionPoints(InjectionPoint.forInstanceMethodsAndFields(type)));
}
@Override
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
public T newInstance(Object... args) {
final T instance = ExceptionUtils.propagate(() -> constructor.newInstance(args));
injector.injectMembers(instance);
return instance;
}
}