public static InjectionCallbackArtifact ensureAsyncInjected(
      TreeLogger logger,
      String packageName,
      String className,
      String outputClass,
      GeneratorContext ctx)
      throws UnableToCompleteException {

    GwtInjectionMap gwtInjectionMap = getInjectionMap(logger, ctx);
    InjectionCallbackArtifact artifact =
        gwtInjectionMap.getOrCreateArtifact(ctx, packageName, className);
    if (artifact.isTargetUnbound()) {
      artifact.bindTo(outputClass);
      ensureProviderClass(
          logger,
          packageName,
          artifact.getSimpleName(),
          artifact.getCanonicalName(),
          artifact.getBoundTarget(),
          ctx);
      logger =
          logger.branch(
              Type.TRACE,
              "Creating asynchronous callback for "
                  + artifact.getCanonicalName()
                  + " -> "
                  + outputClass);
      String generatedName = InjectionUtils.generatedAsyncProviderName(artifact.getGeneratedName());
      String implPackage = artifact.getImplementationPackage();
      PrintWriter printWriter = ctx.tryCreate(logger, implPackage, generatedName);
      if (printWriter == null) {
        logger.log(
            Type.WARN,
            "Could not create the source writer for " + implPackage + "." + generatedName);
        return artifact;
      }
      artifact.addCallback(implPackage + "." + generatedName + ".Deproxy");
      ctx.commitArtifact(logger, artifact);

      ClassSourceFileComposerFactory composer =
          new ClassSourceFileComposerFactory(implPackage, generatedName);
      composer.setPrivacy("public final");

      composer.addImport(com.google.gwt.core.client.GWT.class.getName());
      composer.addImport(RunAsyncCallback.class.getName());
      composer.addImport(Fifo.class.getName());
      composer.addImport(JsFifo.class.getName());
      composer.addImport(AsyncProxy.class.getName());
      composer.addImport(ApplyMethod.class.getName());
      composer.addImport(ReceivesValue.class.getName());
      composer.addImport(ReceiverAdapter.class.getCanonicalName());
      composer.addImport(artifact.getCanonicalName());

      String simpleName = artifact.getSimpleName();
      SourceWriter sw = composer.createSourceWriter(ctx, printWriter);

      sw.println();
      sw.println("static final class Callbacks implements ApplyMethod{");
      sw.indent();
      sw.println("public void apply(Object ... args){");
      sw.println("}");
      sw.outdent();
      sw.println("}");
      sw.println();

      sw.println("static final class Deproxy implements ReceivesValue<" + simpleName + ">{");
      sw.indent();
      sw.println("public final void set(final " + simpleName + " value){");
      sw.indentln("getter = new ReceiverAdapter<" + simpleName + ">(value);");
      sw.println("}");
      sw.outdent();
      sw.println("}");
      sw.println();

      sw.println(
          "private static final class Proxy implements ReceivesValue<ReceivesValue<"
              + simpleName
              + ">>{");
      sw.indent();
      sw.println("public final void set(final ReceivesValue<" + simpleName + "> receiver){");
      sw.indent();

      sw.print("GWT.runAsync(");
      sw.println(artifact.getCanonicalName() + ".class,new Request(receiver));");

      sw.outdent();
      sw.println("}");
      sw.outdent();
      sw.println("}");
      sw.println();

      sw.println("private static final class Request");
      sw.indent();
      sw.println("extends AsyncProxy<" + simpleName + "> ");
      sw.println("implements RunAsyncCallback{");

      DefermentWriter defer = new DefermentWriter(sw);
      defer.setStrategy(DefermentStrategy.NONE);

      sw.println("private static final Fifo<ReceivesValue<" + simpleName + ">> pending =");
      sw.indentln("JsFifo.newFifo();");
      sw.println();

      sw.println("protected Request(ReceivesValue<" + simpleName + "> receiver){");
      sw.indentln("accept(receiver);");
      sw.println("}");
      sw.println();

      sw.println("@Override");
      sw.println("protected final Fifo<ReceivesValue<" + simpleName + ">> pending(){");
      sw.indentln("return pending;");
      sw.println("}");
      sw.println();

      sw.println("protected final void dispatch(){");
      sw.indentln("go();");
      sw.println("}");
      sw.println();

      sw.println("public final void onSuccess(){");
      sw.indent();
      defer.printStart();

      sw.println("final " + simpleName + " value = ");
      sw.print(packageName + "." + InjectionUtils.generatedProviderName(simpleName));
      sw.println(".theProvider.get();");
      sw.println();

      sw.print("final ApplyMethod callbacks = GWT.create(");
      sw.print(packageName + ".impl." + generatedName + ".Callbacks.class");
      sw.println(");");
      sw.println("callbacks.apply(value);");
      sw.println();

      sw.println("apply(value);");
      sw.outdent();
      sw.println("}");
      sw.outdent();
      defer.printFinish();
      sw.println("}");
      sw.println();

      sw.println(
          "private static ReceivesValue<ReceivesValue<" + simpleName + ">> getter = new Proxy();");
      sw.println();

      sw.println("static void request(final ReceivesValue<" + simpleName + "> request){");
      sw.indentln("getter.set(request);");
      sw.println("}");
      sw.println();

      sw.println("static void go(){");
      sw.indentln("request(null);");
      sw.println("}");
      sw.println();

      sw.println("private " + generatedName + "(){}");

      sw.commit(logger);

    } else {
      assert artifact.getBoundTarget().equals(outputClass)
          : "The injection target "
              + artifact.getCanonicalName()
              + " was bound "
              + "to "
              + artifact.getBoundTarget()
              + ", but you tried to bind it again, "
              + "to a different class: "
              + outputClass;
    }
    return artifact;
  }