public static void patch(CtClass c, IPatcher patcher) throws Exception {
    treatClassToPatch(c);

    if (patcher != null) {
      patcher.initClass(c);
    }

    for (CtMethod m : c.getDeclaredMethods()) {
      boolean wasAbstract = false;
      String newBody = null;
      if (Modifier.isAbstract(m.getModifiers())) {
        m.setModifiers(m.getModifiers() - Modifier.ABSTRACT);
        wasAbstract = true;
      }
      if (patcher != null) {
        newBody = patcher.getNewBody(m);
      }
      if (newBody != null) {
        if (newBody.startsWith(AutomaticPatcher.INSERT_BEFORE)) {
          GwtPatcherUtils.insertBefore(
              m, newBody.substring(AutomaticPatcher.INSERT_BEFORE.length()));
        } else if (newBody.startsWith(AutomaticPatcher.INSERT_AFTER)) {
          GwtPatcherUtils.insertAfter(m, newBody.substring(AutomaticPatcher.INSERT_AFTER.length()));
        } else {
          GwtPatcherUtils.replaceImplementation(m, newBody);
        }
      } else if (wasAbstract) {
        if (patcher != null) {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by "
                  + patcher.getClass().getName()
                  + "\"); }");
        } else {
          m.setBody(
              "{ throw new "
                  + UnsupportedOperationException.class.getName()
                  + "(\"Abstract method '"
                  + c.getSimpleName()
                  + "."
                  + m.getName()
                  + "()' is not patched by any declared "
                  + IPatcher.class.getSimpleName()
                  + " instance\"); }");
        }
      }
    }

    if (patcher != null) {
      patcher.finalizeClass(c);
    }
  }
  // this GwtCreateHandler has been introduced to make possible the
  // instanciation of abstract classes
  // that gwt-test-utils doesn't patch right now
  public Object create(Class<?> classLiteral) throws Exception {
    if (classLiteral.isAnnotation()
        || classLiteral.isArray()
        || classLiteral.isEnum()
        || classLiteral.isInterface()
        || !Modifier.isAbstract(classLiteral.getModifiers())) {
      return null;
    }

    Class<?> newClass = cache.get(classLiteral);

    if (newClass != null) {
      return newClass.newInstance();
    }

    CtClass ctClass = GwtClassPool.getCtClass(classLiteral);
    CtClass subClass = GwtClassPool.get().makeClass(classLiteral.getCanonicalName() + "SubClass");

    subClass.setSuperclass(ctClass);

    for (CtMethod m : ctClass.getDeclaredMethods()) {
      if (javassist.Modifier.isAbstract(m.getModifiers())) {
        CtMethod copy = new CtMethod(m, subClass, null);
        subClass.addMethod(copy);
      }
    }

    GwtPatcherUtils.patch(subClass, null);

    newClass = subClass.toClass(GwtClassLoader.get(), null);
    cache.put(classLiteral, newClass);

    return newClass.newInstance();
  }