protected static boolean isCallbackInjected(
     TreeLogger logger, String packageName, String simpleSourceName, GeneratorContext context) {
   try {
     JClassType type =
         context
             .getTypeOracle()
             .findType(packageName + "." + InjectionUtils.generatedCallbackName(simpleSourceName));
     return type != null;
   } catch (Exception e) {
     return false;
   }
 }
  public static boolean ensureProviderClass(
      TreeLogger logger,
      String packageName,
      String simpleName0,
      String canonical,
      String qualifiedSourceName,
      GeneratorContext ctx) {
    String simpleName = SourceUtil.toSourceName(simpleName0);
    String generatedName = InjectionUtils.generatedProviderName(simpleName);
    String cleanedCanonical = SourceUtil.toSourceName(canonical);
    logger.log(Type.DEBUG, "Creating provider for " + packageName + "." + generatedName);

    PrintWriter printWriter = ctx.tryCreate(logger, packageName, generatedName);
    if (printWriter == null) {
      logger.log(Type.TRACE, "Already generated " + generatedName);
      return false;
    }
    logger.log(
        Type.TRACE, "Newly Generating provider " + generatedName + " <- " + qualifiedSourceName);

    ClassSourceFileComposerFactory composer =
        new ClassSourceFileComposerFactory(packageName, generatedName);
    composer.setSuperclass(SingletonInitializer.class.getName() + "<" + simpleName0 + ">");
    composer.addImport(cleanedCanonical);
    composer.addImport(GWT.class.getName());
    composer.addImport(SingletonProvider.class.getName());

    SourceWriter sw = composer.createSourceWriter(ctx, printWriter);

    sw.println("@Override");
    sw.println("public " + simpleName + " initialValue(){");
    sw.indent();

    sw.print("return GWT.<" + cleanedCanonical + ">create(");
    sw.print(SourceUtil.toSourceName(qualifiedSourceName) + ".class");
    sw.println(");");

    sw.outdent();
    sw.println("}");
    sw.println();
    // now, print a static final provider instance
    sw.print("public static final SingletonProvider<");
    sw.print(simpleName0 + "> ");
    sw.print("theProvider = ");
    sw.println("new " + generatedName + "();");
    sw.commit(logger);
    return true;
  }
  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;
  }