/** * Tries to find a data binder reference for an injected {@link Model}. * * @param inst the injectable instance * @return the data binder reference or null if not found. */ private static DataBinderRef lookupBinderForModel(final InjectableInstance<?> inst) { Statement dataBinderRef; MetaClass dataModelType; InjectUtil.BeanMetric beanMetric = InjectUtil.getFilteredBeanMetric( inst.getInjectionContext(), inst.getInjector().getInjectedType(), Model.class); if (!beanMetric.getAllInjectors().isEmpty()) { final Collection<Object> allInjectors = beanMetric.getAllInjectors(); if (allInjectors.size() > 1) { throw new GenerationException("Multiple @Models injected in " + inst.getEnclosingType()); } else if (allInjectors.size() == 1) { final Object injectorElement = allInjectors.iterator().next(); if (injectorElement instanceof MetaConstructor || injectorElement instanceof MetaMethod) { final MetaParameter mp = beanMetric.getConsolidatedMetaParameters().iterator().next(); dataModelType = mp.getType(); assertTypeIsBindable(dataModelType); dataBinderRef = inst.getTransientValue(TRANSIENT_BINDER_VALUE, DataBinder.class); inst.ensureMemberExposed(); } else { final MetaField field = (MetaField) allInjectors.iterator().next(); dataModelType = field.getType(); assertTypeIsBindable(dataModelType); dataBinderRef = inst.getTransientValue(TRANSIENT_BINDER_VALUE, DataBinder.class); inst.getInjectionContext().addExposedField(field, PrivateAccessType.Both); } return new DataBinderRef(dataModelType, dataBinderRef); } } else { List<MetaField> modelFields = inst.getInjector().getInjectedType().getFieldsAnnotatedWith(Model.class); if (!modelFields.isEmpty()) { throw new GenerationException( "Found one or more fields annotated with @Model but missing @Inject " + modelFields.toString()); } List<MetaParameter> modelParameters = inst.getInjector().getInjectedType().getParametersAnnotatedWith(Model.class); if (!modelParameters.isEmpty()) { throw new GenerationException( "Found one or more constructor or method parameters annotated with @Model but missing @Inject " + modelParameters.toString()); } } return null; }
@Override public Statement getBeanInstance(final InjectableInstance injectableInstance) { final IOCProcessingContext pCtx = injectableInstance.getInjectionContext().getProcessingContext(); pCtx.append(Stmt.declareFinalVariable(varName, proxyClass, newObject(proxyClass))); final MetaClass proxyResolverRef = parameterizedAs(ProxyResolver.class, typeParametersOf(proxiedType)); final BlockBuilder<AnonymousClassStructureBuilder> proxyResolverBody = newObject(proxyResolverRef) .extend().publicOverridesMethod("resolve", Parameter.of(proxiedType, "obj")); final Statement proxyResolver = proxyResolverBody._( ProxyMaker.closeProxy(Refs.get(varName), Refs.get("obj")) ).finish().finish(); proxyResolverBody._(Stmt.loadVariable("context").invoke("addProxyReference", Refs.get(varName), Refs.get("obj"))); pCtx.append(loadVariable("context").invoke("addUnresolvedProxy", proxyResolver, proxiedType, qualifyingMetadata.getQualifiers())); for (final Statement statement : closeStatements) { proxyResolverBody.append(statement); } setRendered(true); return loadVariable(varName); }
/** * Tries to find a reference for an injected {@link AutoBound} data binder. * * @return the data binder reference or null if not found. */ private static DataBinderRef lookupAutoBoundBinder(final InjectableInstance<?> inst) { Statement dataBinderRef = null; MetaClass dataModelType = null; InjectUtil.BeanMetric beanMetric = InjectUtil.getFilteredBeanMetric( inst.getInjectionContext(), inst.getInjector().getInjectedType(), AutoBound.class); final Collection<Object> allInjectors = beanMetric.getAllInjectors(); if (allInjectors.size() > 1) { throw new GenerationException( "Multiple @AutoBound data binders injected in " + inst.getEnclosingType()); } else if (allInjectors.size() == 1) { final Object injectorElement = allInjectors.iterator().next(); if (injectorElement instanceof MetaConstructor || injectorElement instanceof MetaMethod) { final MetaParameter mp = beanMetric.getConsolidatedMetaParameters().iterator().next(); assertTypeIsDataBinder(mp.getType()); dataModelType = (MetaClass) mp.getType().getParameterizedType().getTypeParameters()[0]; dataBinderRef = inst.getInjectionContext().getInlineBeanReference(mp); inst.ensureMemberExposed(); } else { final MetaField field = (MetaField) allInjectors.iterator().next(); assertTypeIsDataBinder(field.getType()); dataModelType = (MetaClass) field.getType().getParameterizedType().getTypeParameters()[0]; dataBinderRef = Stmt.invokeStatic( inst.getInjectionContext().getProcessingContext().getBootstrapClass(), PrivateAccessUtil.getPrivateFieldInjectorName(field), Variable.get(inst.getInjector().getInstanceVarName())); inst.getInjectionContext().addExposedField(field, PrivateAccessType.Both); } } else { final MetaClass declaringClass = inst.getInjector().getInjectedType(); for (final MetaField field : declaringClass.getFields()) { if (field.isAnnotationPresent(AutoBound.class)) { assertTypeIsDataBinder(field.getType()); dataModelType = (MetaClass) field.getType().getParameterizedType().getTypeParameters()[0]; dataBinderRef = Stmt.invokeStatic( inst.getInjectionContext().getProcessingContext().getBootstrapClass(), PrivateAccessUtil.getPrivateFieldInjectorName(field), Variable.get(inst.getInjector().getInstanceVarName())); inst.getInjectionContext().addExposedField(field, PrivateAccessType.Both); break; } } } return (dataBinderRef != null) ? new DataBinderRef(dataModelType, dataBinderRef) : null; }
@Override public Statement getBeanInstance(final InjectableInstance injectableInstance) { final MetaClass type; final MetaParameterizedType pType; switch (injectableInstance.getTaskType()) { case Type: return null; case PrivateField: case Field: final MetaField field = injectableInstance.getField(); type = field.getType(); pType = type.getParameterizedType(); break; case Parameter: final MetaParameter parm = injectableInstance.getParm(); type = parm.getType(); pType = type.getParameterizedType(); break; default: throw new RuntimeException("illegal task type: " + injectableInstance.getEnclosingType()); } final MetaType[] typeArgs = pType.getTypeParameters(); final MetaClass[] typeArgsClasses = new MetaClass[typeArgs.length]; for (int i = 0; i < typeArgs.length; i++) { final MetaType argType = typeArgs[i]; if (argType instanceof MetaClass) { typeArgsClasses[i] = (MetaClass) argType; } else if (argType instanceof MetaParameterizedType) { typeArgsClasses[i] = (MetaClass) ((MetaParameterizedType) argType).getRawType(); } } final Annotation[] qualifiers = injectableInstance.getQualifiers(); final BlockBuilder<?> block = injectableInstance.getInjectionContext().getProcessingContext().getBlockBuilder(); final MetaClass providerCreationalCallback = MetaClassFactory.parameterizedAs( CreationalCallback.class, MetaClassFactory.typeParametersOf(providerInjector.getInjectedType())); final String varName = InjectUtil.getVarNameFromType( providerInjector.getConcreteInjectedType(), injectableInstance); final Statement valueRef; if (providerInjector.isSingleton() && providerInjector.isRendered()) { valueRef = Stmt.loadVariable("beanInstance") .invoke("provide", typeArgsClasses, qualifiers.length != 0 ? qualifiers : null); } else { valueRef = Stmt.load(null); } block.append( Stmt.declareFinalVariable( varName, providerCreationalCallback, Stmt.newObject(providerCreationalCallback) .extend() .publicOverridesMethod( "callback", Parameter.of(providerInjector.getInjectedType(), "beanInstance")) .append( Stmt.loadVariable(InjectUtil.getVarNameFromType(type, injectableInstance)) .invoke("callback", valueRef)) .append(Stmt.loadVariable("async").invoke("finish", Refs.get("this"))) .finish() .publicOverridesMethod("toString") .append( Stmt.load(providerInjector.getInjectedType()).invoke("getName").returnValue()) .finish() .finish())); block.append(Stmt.loadVariable("async").invoke("wait", Refs.get(varName))); block.append( Stmt.loadVariable(providerInjector.getCreationalCallbackVarName()) .invoke("getInstance", Refs.get(varName), Refs.get("context"))); return null; }