Package org.jboss.errai.ioc.rebind.ioc.injector

Source Code of org.jboss.errai.ioc.rebind.ioc.injector.AsyncInjectUtil

/*
* Copyright 2013 JBoss, by Red Hat, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jboss.errai.ioc.rebind.ioc.injector;

import org.jboss.errai.codegen.Cast;
import org.jboss.errai.codegen.Context;
import org.jboss.errai.codegen.DefParameters;
import org.jboss.errai.codegen.Parameter;
import org.jboss.errai.codegen.Statement;
import org.jboss.errai.codegen.builder.AnonymousClassStructureBuilder;
import org.jboss.errai.codegen.builder.BlockBuilder;
import org.jboss.errai.codegen.builder.impl.ObjectBuilder;
import org.jboss.errai.codegen.exception.UnproxyableClassException;
import org.jboss.errai.codegen.meta.MetaClass;
import org.jboss.errai.codegen.meta.MetaClassFactory;
import org.jboss.errai.codegen.meta.MetaConstructor;
import org.jboss.errai.codegen.meta.MetaField;
import org.jboss.errai.codegen.meta.MetaMethod;
import org.jboss.errai.codegen.meta.MetaParameter;
import org.jboss.errai.codegen.util.Refs;
import org.jboss.errai.codegen.util.Stmt;
import org.jboss.errai.ioc.client.container.async.CreationalCallback;
import org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCProcessingContext;
import org.jboss.errai.ioc.rebind.ioc.exception.InjectionFailure;
import org.jboss.errai.ioc.rebind.ioc.exception.UnsatisfiedDependenciesException;
import org.jboss.errai.ioc.rebind.ioc.injector.api.AsyncDecoratorTask;
import org.jboss.errai.ioc.rebind.ioc.injector.api.AsyncInjectionTask;
import org.jboss.errai.ioc.rebind.ioc.injector.api.ConstructionStatusCallback;
import org.jboss.errai.ioc.rebind.ioc.injector.api.ConstructionStrategy;
import org.jboss.errai.ioc.rebind.ioc.injector.api.ConstructionType;
import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectableInstance;
import org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionContext;
import org.jboss.errai.ioc.rebind.ioc.injector.api.TaskType;
import org.jboss.errai.ioc.rebind.ioc.injector.async.AsyncInjectorResolveCallback;
import org.jboss.errai.ioc.rebind.ioc.injector.async.AsyncProxyInjector;
import org.jboss.errai.ioc.rebind.ioc.injector.async.AsyncTypeInjector;
import org.jboss.errai.ioc.rebind.ioc.metadata.QualifyingMetadata;

import javax.inject.Provider;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.ArrayList;
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")
                .append(Stmt.nestedCall(Stmt.newObject(type)).returnValue())
                .finish().finish();

            processingContext.append(Stmt.declareFinalVariable(injector.getInstanceVarName(), type,
                Stmt.loadVariable("context").invoke("getWiredOrNew", Refs.get("beanRef"), newObjectCallback)));
          }
          else {
            processingContext.append(
                Stmt.declareVariable(type)
                    .asFinal()
                    .named(injector.getInstanceVarName())
                    .initializeWith(Stmt.newObject(type))

            );
          }

          callback.beanConstructed(ConstructionType.FIELD);

          handleAsyncInjectionTasks(ctx, injectionTasks);

          if (!postConstructTasks.isEmpty() || !preDestroyTasks.isEmpty()) {
            pushFinishRunnable(ctx);

            InjectUtil.doPostConstruct(ctx, injector, postConstructTasks);
            InjectUtil.doPreDestroy(ctx, injector, preDestroyTasks);

            processingContext.popBlockBuilder();
          }
        }
      };
    }
  }

  private static void pushFinishRunnable(final InjectionContext ctx) {
    final BlockBuilder<?> blockBuilder = ctx.getProcessingContext().getBlockBuilder();

    final BlockBuilder<AnonymousClassStructureBuilder> run = Stmt.newObject(Runnable.class)
        .extend().publicOverridesMethod("run");

    ctx.getProcessingContext().pushBlockBuilder(run);

    final ObjectBuilder objectBuilder = run.finish().finish();

    blockBuilder.append(Stmt.loadVariable("async").invoke("runOnFinish", objectBuilder));
  }

  private static void handleAsyncInjectionTasks(final InjectionContext ctx,
                                                final List<AsyncInjectionTask> tasks) {
    for (final AsyncInjectionTask task : tasks) {
      if (!task.doTask(ctx)) {
        throw new InjectionFailure("could perform injection task: " + task);
      }
    }
  }

  private static List<AsyncInjectionTask> scanForTasks(final Injector injector,
                                                       final InjectionContext ctx,
                                                       final MetaClass type) {
    final List<AsyncInjectionTask> accumulator = new ArrayList<AsyncInjectionTask>();
    final Set<Class<? extends Annotation>> decorators = ctx.getDecoratorAnnotations();

    for (final Class<? extends Annotation> decorator : decorators) {
      if (type.isAnnotationPresent(decorator)) {
        accumulator.add(new AsyncInjectionTask(injector, type));
      }
    }

    MetaClass visit = type;

    do {
      for (final MetaField field : visit.getDeclaredFields()) {
        if (InjectUtil.isInjectionPoint(ctx, field)) {
          accumulator.add(new AsyncInjectionTask(injector, field));
        }

        ElementType[] elTypes;
        for (final Class<? extends Annotation> a : decorators) {
          elTypes = a.isAnnotationPresent(Target.class) ? a.getAnnotation(Target.class).value()
              : new ElementType[]{ElementType.FIELD};

          for (final ElementType elType : elTypes) {
            switch (elType) {
              case FIELD:
                if (field.isAnnotationPresent(a)) {
                  accumulator.add(new AsyncDecoratorTask(injector, field, ctx.getDecorator(a)));
                }
                break;
            }
          }
        }
      }

      for (final MetaMethod meth : visit.getDeclaredMethods()) {
        if (InjectUtil.isInjectionPoint(ctx, meth)) {
          accumulator.add(new AsyncInjectionTask(injector, meth));
        }

        for (final Class<? extends Annotation> a : decorators) {
          final ElementType[] elTypes = a.isAnnotationPresent(Target.class) ? a.getAnnotation(Target.class).value()
              : new ElementType[]{ElementType.METHOD};

          for (final ElementType elType : elTypes) {
            switch (elType) {
              case METHOD:
                if (meth.isAnnotationPresent(a)) {
                  accumulator.add(new AsyncDecoratorTask(injector, meth, ctx.getDecorator(a)));
                }
                break;
              case PARAMETER:
                for (final MetaParameter parameter : meth.getParameters()) {
                  if (parameter.isAnnotationPresent(a)) {
                    final AsyncDecoratorTask task = new AsyncDecoratorTask(injector, parameter, ctx.getDecorator(a));
                    accumulator.add(task);
                  }
                }
            }
          }
        }
      }
    }
    while ((visit = visit.getSuperClass()) != null);

    return accumulator;
  }

  private static List<MetaConstructor> scanForConstructorInjectionPoints(final Injector injector,
                                                                         final InjectionContext ctx,
                                                                         final MetaClass type,
                                                                         final List<AsyncInjectionTask> tasks) {
    final List<MetaConstructor> accumulator = new ArrayList<MetaConstructor>();
    final Set<Class<? extends Annotation>> decorators = ctx.getDecoratorAnnotations();

    for (final MetaConstructor cns : type.getConstructors()) {
      if (InjectUtil.isInjectionPoint(ctx, cns)) {
        accumulator.add(cns);
      }

      ElementType[] elTypes;
      for (final Class<? extends Annotation> a : decorators) {
        elTypes = a.isAnnotationPresent(Target.class) ? a.getAnnotation(Target.class).value()
            : new ElementType[]{ElementType.FIELD};

        for (final ElementType elType : elTypes) {
          switch (elType) {
            case CONSTRUCTOR:
              if (cns.isAnnotationPresent(a)) {
                tasks.add(new AsyncDecoratorTask(injector, cns, ctx.getDecorator(a)));
              }
              break;
            case PARAMETER:
              for (final MetaParameter parameter : cns.getParameters()) {
                if (parameter.isAnnotationPresent(a)) {
                  final AsyncDecoratorTask task = new AsyncDecoratorTask(injector, parameter, ctx.getDecorator(a));
                  tasks.add(task);
                }
              }
          }
        }
      }
    }

    return accumulator;
  }


  public static Statement getInjectorOrProxy(final InjectionContext ctx,
                                             final InjectableInstance injectableInstance,
                                             final MetaClass clazz,
                                             final QualifyingMetadata qualifyingMetadata,
                                             final AsyncInjectorResolveCallback... callbacks) {

    return getInjectorOrProxy(ctx, injectableInstance, clazz, qualifyingMetadata, false, callbacks);
  }


  public static Statement getInjectorOrProxy(final InjectionContext ctx,
                                             final InjectableInstance injectableInstance,
                                             final MetaClass clazz,
                                             final QualifyingMetadata qualifyingMetadata,
                                             final boolean alwaysProxyDependent,
                                             final AsyncInjectorResolveCallback... callbacks) {

    if (ctx.isInjectableQualified(clazz, qualifyingMetadata)) {
      final Injector inj = ctx.getQualifiedInjector(clazz, qualifyingMetadata);

      for (final AsyncInjectorResolveCallback cb : callbacks) {
        cb.onResolved(inj);
      }

      /**
       * Special handling for cycles. If two beans directly depend on each other, we shimmy in a call to the
       * binding reference to check the context for the instance to avoid a hanging duplicate reference. It is to
       * ensure only one instance of each bean is created.
       */
      if (ctx.cycles(injectableInstance.getEnclosingType(), clazz) && inj instanceof AsyncTypeInjector) {
        return Stmt.loadVariable("context").invoke("getInstanceOrNew",
            Refs.get(inj.getCreationalCallbackVarName()),
            Refs.get(InjectUtil.getVarNameFromType(inj.getConcreteInjectedType(), injectableInstance)),
            inj.getInjectedType(),
            inj.getQualifyingMetadata().getQualifiers());
      }

      return inj.getBeanInstance(injectableInstance);
    }
    else {
      //todo: refactor the BootstrapInjectionContext to provide a cleaner API for interface delegates

      // try to inject it
      try {
        if (ctx.isInjectorRegistered(clazz, qualifyingMetadata)) {
          final Injector inj = ctx.getQualifiedInjector(clazz, qualifyingMetadata);

          if (inj.isProvider()) {
            if (inj.isStatic()) {
              for (final AsyncInjectorResolveCallback cb : callbacks) {
                cb.onResolved(inj);
              }

              return inj.getBeanInstance(injectableInstance);
            }

            /**
             * Inform the caller that we are in a proxy and that the operation they're doing must
             * necessarily be done within the ProxyResolver resolve operation since this provider operation
             * relies on a bean which is not yet available.
             */
            ctx.recordCycle(inj.getEnclosingType(), injectableInstance.getEnclosingType());

            final AsyncProxyInjector proxyInject = getOrCreateProxy(ctx, inj.getEnclosingType(), qualifyingMetadata);

            boolean pushedProxy = false;

            try {
              if (injectableInstance.getTaskType() == TaskType.Parameter
                  && injectableInstance.getConstructor() != null) {
                // eek! a producer element is produced by this bean and injected into it's own constructor!
                final AsyncProxyInjector producedElementProxy
                    = getOrCreateProxy(ctx, inj.getInjectedType(), qualifyingMetadata);

                for (final AsyncInjectorResolveCallback cb : callbacks) {
                  cb.onResolved(producedElementProxy);
                }

                return producedElementProxy.getBeanInstance(injectableInstance);
              }
              else {
                ctx.getProcessingContext().pushBlockBuilder(proxyInject.getProxyResolverBlockBuilder());
                pushedProxy = true;
                ctx.markOpenProxy();

                for (final AsyncInjectorResolveCallback cb : callbacks) {
                  cb.onResolved(proxyInject);
                }

                return proxyInject.getBeanInstance(injectableInstance);
              }
            }
            finally {
              if (!ctx.isProxyOpen() && pushedProxy) {
                ctx.getProcessingContext().popBlockBuilder();
              }
            }

          }
          else if (inj.isSoftDisabled()
              || (inj.isDependent() &&
              (!alwaysProxyDependent || !ctx.typeContainsGraphCycles(inj.getInjectedType())))) {

            inj.setEnabled(true);
            if (inj.isCreated() && !inj.isRendered()) {
              throw new InjectionFailure("unresolveable cycle on dependent scoped bean: "
                  + inj.getInjectedType().getFullyQualifiedName() + "; does the bean intersect with a normal scope?");
            }

            for (final AsyncInjectorResolveCallback cb : callbacks) {
              cb.onResolved(inj);
            }

            return inj.getBeanInstance(injectableInstance);
          }
        }
      }
      catch (InjectionFailure e) {
        e.printStackTrace();
      }

      if (!ctx.isTypeInjectable(clazz)) {
        ctx.recordCycle(clazz, injectableInstance.getEnclosingType());
        final AsyncProxyInjector proxyInject = getOrCreateProxy(ctx, clazz, qualifyingMetadata);

        for (final AsyncInjectorResolveCallback cb : callbacks) {
          cb.onResolved(proxyInject);
        }

        return proxyInject.getBeanInstance(injectableInstance);
      }
      else {
        throw new InjectionFailure("cannot resolve injectable bean for type: " + clazz.getFullyQualifiedName()
            + "; qualified by: " + qualifyingMetadata.toString());
      }
    }
  }

  public static AsyncProxyInjector getOrCreateProxy(final InjectionContext ctx,
                                                    final MetaClass clazz,
                                                    final QualifyingMetadata qualifyingMetadata) {
    final AsyncProxyInjector proxyInjector;
    if (ctx.isProxiedInjectorRegistered(clazz, qualifyingMetadata)) {
      proxyInjector = (AsyncProxyInjector)
          ctx.getProxiedInjector(clazz, qualifyingMetadata);
      return proxyInjector;

    }
    else if (ctx.hasTopLevelType(clazz)) {
      proxyInjector = new AsyncProxyInjector(ctx.getProcessingContext(), clazz, qualifyingMetadata);
      ctx.addProxiedInjector(proxyInjector);
      return proxyInjector;
    }
    else {
      throw new InjectionFailure("can't resolve bean: " + clazz + " (" + qualifyingMetadata.toString() + ")");
    }
  }

  public static Statement[] resolveInjectionDependencies(final MetaParameter[] parms,
                                                         final InjectionContext ctx,
                                                         final MetaMethod method,
                                                         final AsyncInjectorResolveCallback... callbacks) {
    return resolveInjectionDependencies(parms, ctx, method, true, callbacks);
  }

  public static Statement[] resolveInjectionDependencies(final MetaParameter[] parms,
                                                         final InjectionContext ctx,
                                                         final MetaMethod method,
                                                         final boolean inlineReference,
                                                         final AsyncInjectorResolveCallback... callbacks) {

    final MetaClass[] parmTypes = InjectUtil.parametersToClassTypeArray(parms);
    final Statement[] parmValues = new Statement[parmTypes.length];

    for (int i = 0; i < parmTypes.length; i++) {
      Statement stmt;
      try {
        final InjectableInstance injectableInstance = InjectableInstance.getParameterInjectedInstance(
            parms[i],
            null,
            ctx);

        stmt = getInjectorOrProxy(ctx, injectableInstance, parmTypes[i],
            ctx.getProcessingContext().getQualifyingMetadataFactory().createFrom(parms[i].getAnnotations()), callbacks);

        ctx.getProcessingContext().append(stmt);


        if (inlineReference) {
          stmt = recordInlineReference(ctx, parms[i]);
        }
      }
      catch (InjectionFailure e) {
        e.setTarget(method.getDeclaringClass() + "." + method.getName() + DefParameters.from(method)
            .generate(Context.create()));
        throw e;
      }

      parmValues[i] = stmt;
    }

    return parmValues;
  }

  public static Statement[] resolveInjectionDependencies(final MetaParameter[] parms,
                                                         final InjectionContext ctx,
                                                         final MetaConstructor constructor) {
    final MetaClass[] parmTypes = InjectUtil.parametersToClassTypeArray(parms);
    final Statement[] parmValues = new Statement[parmTypes.length];

    for (int i = 0; i < parmTypes.length; i++) {
      final Statement stmt;
      final MetaClass parmType = parmTypes[i];
      final MetaParameter metaParameter = parms[i];
      try {
        final QualifyingMetadata qualifyingMetadata = ctx.getProcessingContext().getQualifyingMetadataFactory().createFrom(
            parms[i].getAnnotations()
        );

        // Get the injection value.
        final BlockBuilder<?> blockBuilder = ctx.getProcessingContext().getBlockBuilder();


        blockBuilder.append(getInjectorOrProxy(
            ctx,
            InjectableInstance.getParameterInjectedInstance(parms[i], null, ctx),
            parmType,
            qualifyingMetadata,
            true, new AsyncInjectorResolveCallback() {
          @Override
          public void onResolved(final Injector resolvedInjector) {

            final MetaClass injectedType = resolvedInjector.getInjectedType();
            final MetaClass creationType = MetaClassFactory
                .parameterizedAs(CreationalCallback.class, MetaClassFactory.typeParametersOf(injectedType));

            final Statement callback = Stmt.newObject(creationType).extend()
                .publicOverridesMethod("callback", Parameter.of(injectedType, "beanInstance"))
                .append(Stmt.loadVariable("async").invoke("finish", Refs.get("this"), Refs.get("beanInstance")))
                .finish()
                .finish();

            final String varNameFromType = InjectUtil.getVarNameFromType(injectedType, metaParameter);
            blockBuilder.append(Stmt.declareFinalVariable(varNameFromType, creationType, callback));
            blockBuilder.append(Stmt.loadVariable("async").invoke("waitConstruct", Refs.get(varNameFromType)));
          }
        }
        ));
        // Record the statement which can be used to access the reference to the injected bean in-line.
        // For instance, for code decoration.
        stmt = recordInlineReference(
            ctx,
            parms[i]
        );

        ctx.closeProxyIfOpen();
      }
      catch (UnproxyableClassException e) {
        final String err = "your object graph has cyclical dependencies and the cycle could not be proxied. " +
            "use of the @Dependent scope and @New qualifier may not " +
            "produce properly initalized objects for: " + parmType.getFullyQualifiedName() + "\n" +
            "\t Offending node: " + constructor.getDeclaringClass().getFullyQualifiedName() + "\n" +
            "\t Note          : this issue can possibly be resolved by making "
            + e.getUnproxyableClass() + " proxyable. Introduce a default no-arg constructor and make sure the " +
            "class is non-final.";

        throw UnsatisfiedDependenciesException.createWithSingleParameterFailure(parms[i], constructor.getDeclaringClass(),
            parms[i].getType(), err);
      }
      catch (InjectionFailure e) {
        e.setTarget(constructor.getDeclaringClass() + "." + DefParameters.from(constructor)
            .generate(Context.create()));
        throw e;
      }

      parmValues[i] = stmt;
    }

    return parmValues;
  }

  private static Statement recordInlineReference(final InjectionContext ctx,
                                                 final MetaParameter parm) {

    final Injector injector = ctx.getQualifiedInjector(parm.getType(), parm.getAnnotations());

    final Statement stmt = Cast.to(parm.getType(), Stmt.loadVariable("async").invoke("getBeanValue",
        Refs.get(InjectUtil.getVarNameFromType(injector.getConcreteInjectedType(), parm))));

    ctx.addInlineBeanReference(parm, stmt);
    return stmt;
  }

  public static Statement generateCallback(final MetaClass type,
                                           final Statement... fieldAccessStmt) {

    final MetaClass callbackClass = MetaClassFactory.parameterizedAs(CreationalCallback.class,
        MetaClassFactory.typeParametersOf(type));

    final BlockBuilder<AnonymousClassStructureBuilder> statements = Stmt.newObject(callbackClass).extend()
        .publicOverridesMethod("callback", Parameter.of(type, "bean"));

    for (final Statement stmt : fieldAccessStmt) {
      statements.append(stmt);
    }

    final ObjectBuilder finish = statements.finish()
        .publicOverridesMethod("toString")
        .append(Stmt.load(type).invoke("getName").returnValue()).finish()
        .finish();

    return finish;
  }

}
TOP

Related Classes of org.jboss.errai.ioc.rebind.ioc.injector.AsyncInjectUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.