/**
   * 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;
  }
Beispiel #2
0
  @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);
  }
  @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;
  }
  /**
   * 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;
  }