import java.util.List;
import java.util.Set;
public class AsyncInjectUtil {
public static ConstructionStrategy getConstructionStrategy(final Injector injector, final InjectionContext ctx) {
final MetaClass type = injector.getInjectedType();
final List<AsyncInjectionTask> injectionTasks = new ArrayList<AsyncInjectionTask>();
final List<MetaConstructor> constructorInjectionPoints
= scanForConstructorInjectionPoints(injector, ctx, type, injectionTasks);
injectionTasks.addAll(scanForTasks(injector, ctx, type));
final List<MetaMethod> postConstructTasks = InjectUtil.scanForPostConstruct(type);
final List<MetaMethod> preDestroyTasks = InjectUtil.scanForPreDestroy(type);
for (final Class<? extends Annotation> a : ctx.getDecoratorAnnotationsBy(ElementType.TYPE)) {
if (type.isAnnotationPresent(a)) {
final AsyncDecoratorTask task = new AsyncDecoratorTask(injector, type, ctx.getDecorator(a));
injectionTasks.add(task);
}
}
if (!constructorInjectionPoints.isEmpty()) {
if (constructorInjectionPoints.size() > 1) {
throw new InjectionFailure("more than one constructor in "
+ type.getFullyQualifiedName() + " is marked as the injection point!");
}
final MetaConstructor constructor = constructorInjectionPoints.get(0);
return new ConstructionStrategy() {
@Override
public void generateConstructor(final ConstructionStatusCallback callback) {
final Statement[] parameterStatements
= resolveInjectionDependencies(constructor.getParameters(), ctx, constructor);
if (injector.isSingleton() && injector.isCreated()) return;
final IOCProcessingContext processingContext = ctx.getProcessingContext();
final BlockBuilder<AnonymousClassStructureBuilder> runBlock = Stmt.newObject(Runnable.class)
.extend().publicOverridesMethod("run");
if (injector.isSingleton() && ctx.typeContainsGraphCycles(type)) {
final MetaClass providerType = MetaClassFactory.parameterizedAs(Provider.class,
MetaClassFactory.typeParametersOf(type));
final Statement newObjectCallback = Stmt.newObject(providerType)
.extend()
.publicOverridesMethod("get")
.append(Stmt.nestedCall(Stmt.newObject(type, parameterStatements)).returnValue())
.finish().finish();
runBlock.append(Stmt.declareFinalVariable(injector.getInstanceVarName(), type,
Stmt.loadVariable("context").invoke("getWiredOrNew", Refs.get("beanRef"), newObjectCallback)));
}
else {
runBlock.append(Stmt.declareFinalVariable(injector.getInstanceVarName(), type, Stmt.newObject(type, parameterStatements)));
}
final Statement finishedCallback = runBlock
.append(Stmt.loadVariable("async").invoke("setConstructedObject", Refs.get(injector.getInstanceVarName())))
.finish()
.finish();
processingContext.append(Stmt.loadVariable("async").invoke("setOnConstruct", finishedCallback));
processingContext.pushBlockBuilder(runBlock);
callback.beanConstructed(ConstructionType.CONSTRUCTOR);
handleAsyncInjectionTasks(ctx, injectionTasks);
if (!postConstructTasks.isEmpty() || !preDestroyTasks.isEmpty()) {
pushFinishRunnable(ctx);
InjectUtil.doPostConstruct(ctx, injector, postConstructTasks);
InjectUtil.doPreDestroy(ctx, injector, preDestroyTasks);
processingContext.popBlockBuilder(); // once for the finish runnable
}
processingContext.popBlockBuilder(); // once for the constructed object callback
}
};
}
else {
// field injection
if (!InjectUtil.hasDefaultConstructor(type))
throw new InjectionFailure("there is no public default constructor or suitable injection constructor for type: "
+ type.getFullyQualifiedName());
return new ConstructionStrategy() {
@Override
public void generateConstructor(final ConstructionStatusCallback callback) {
if (injector.isSingleton() && injector.isCreated()) return;
final IOCProcessingContext processingContext = ctx.getProcessingContext();
if (injector.isSingleton() && ctx.typeContainsGraphCycles(type)) {
final MetaClass providerType = MetaClassFactory.parameterizedAs(Provider.class,
MetaClassFactory.typeParametersOf(type));
final Statement newObjectCallback = Stmt.newObject(providerType)
.extend()
.publicOverridesMethod("get")