static Object js_createAdpter(Context cx, Scriptable scope, Object[] args) {
    int N = args.length;
    if (N == 0) {
      throw ScriptRuntime.typeError0("msg.adapter.zero.args");
    }

    Class superClass = null;
    Class[] intfs = new Class[N - 1];
    int interfaceCount = 0;
    for (int i = 0; i != N - 1; ++i) {
      Object arg = args[i];
      if (!(arg instanceof NativeJavaClass)) {
        throw ScriptRuntime.typeError2(
            "msg.not.java.class.arg", String.valueOf(i), ScriptRuntime.toString(arg));
      }
      Class c = ((NativeJavaClass) arg).getClassObject();
      if (!c.isInterface()) {
        if (superClass != null) {
          throw ScriptRuntime.typeError2("msg.only.one.super", superClass.getName(), c.getName());
        }
        superClass = c;
      } else {
        intfs[interfaceCount++] = c;
      }
    }

    if (superClass == null) superClass = ScriptRuntime.ObjectClass;

    Class[] interfaces = new Class[interfaceCount];
    System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
    Scriptable obj = ScriptRuntime.toObject(cx, scope, args[N - 1]);

    Class adapterClass = getAdapterClass(scope, superClass, interfaces, obj);

    Class[] ctorParms = {ScriptRuntime.ContextFactoryClass, ScriptRuntime.ScriptableClass};
    Object[] ctorArgs = {cx.getFactory(), obj};
    try {
      Object adapter = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
      return getAdapterSelf(adapterClass, adapter);
    } catch (Exception ex) {
      throw Context.throwAsScriptRuntimeEx(ex);
    }
  }
  static Object js_createAdapter(Context cx, Scriptable scope, Object[] args) {
    int N = args.length;
    if (N == 0) {
      throw ScriptRuntime.typeError0("msg.adapter.zero.args");
    }

    // Expected arguments:
    // Any number of NativeJavaClass objects representing the super-class
    // and/or interfaces to implement, followed by one NativeObject providing
    // the implementation, followed by any number of arguments to pass on
    // to the (super-class) constructor.

    int classCount;
    for (classCount = 0; classCount < N - 1; classCount++) {
      Object arg = args[classCount];
      // We explicitly test for NativeObject here since checking for
      // instanceof ScriptableObject or !(instanceof NativeJavaClass)
      // would fail for a Java class that isn't found in the class path
      // as NativeJavaPackage extends ScriptableObject.
      if (arg instanceof NativeObject) {
        break;
      }
      if (!(arg instanceof NativeJavaClass)) {
        throw ScriptRuntime.typeError2(
            "msg.not.java.class.arg", String.valueOf(classCount), ScriptRuntime.toString(arg));
      }
    }
    Class<?> superClass = null;
    Class<?>[] intfs = new Class[classCount];
    int interfaceCount = 0;
    for (int i = 0; i < classCount; ++i) {
      Class<?> c = ((NativeJavaClass) args[i]).getClassObject();
      if (!c.isInterface()) {
        if (superClass != null) {
          throw ScriptRuntime.typeError2("msg.only.one.super", superClass.getName(), c.getName());
        }
        superClass = c;
      } else {
        intfs[interfaceCount++] = c;
      }
    }

    if (superClass == null) {
      superClass = ScriptRuntime.ObjectClass;
    }

    Class<?>[] interfaces = new Class[interfaceCount];
    System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
    // next argument is implementation, must be scriptable
    Scriptable obj = ScriptableObject.ensureScriptable(args[classCount]);

    Class<?> adapterClass = getAdapterClass(scope, superClass, interfaces, obj);
    Object adapter;

    int argsCount = N - classCount - 1;
    try {
      if (argsCount > 0) {
        // Arguments contain parameters for super-class constructor.
        // We use the generic Java method lookup logic to find and
        // invoke the right constructor.
        Object[] ctorArgs = new Object[argsCount + 2];
        ctorArgs[0] = obj;
        ctorArgs[1] = cx.getFactory();
        System.arraycopy(args, classCount + 1, ctorArgs, 2, argsCount);
        // TODO: cache class wrapper?
        NativeJavaClass classWrapper = new NativeJavaClass(scope, adapterClass, true);
        NativeJavaMethod ctors = classWrapper.members.ctors;
        int index = ctors.findCachedFunction(cx, ctorArgs);
        if (index < 0) {
          String sig = NativeJavaMethod.scriptSignature(args);
          throw Context.reportRuntimeError2("msg.no.java.ctor", adapterClass.getName(), sig);
        }

        // Found the constructor, so try invoking it.
        adapter = NativeJavaClass.constructInternal(ctorArgs, ctors.methods[index]);
      } else {
        Class<?>[] ctorParms = {ScriptRuntime.ScriptableClass, ScriptRuntime.ContextFactoryClass};
        Object[] ctorArgs = {obj, cx.getFactory()};
        adapter = adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
      }

      Object self = getAdapterSelf(adapterClass, adapter);
      // Return unwrapped JavaAdapter if it implements Scriptable
      if (self instanceof Wrapper) {
        Object unwrapped = ((Wrapper) self).unwrap();
        if (unwrapped instanceof Scriptable) {
          if (unwrapped instanceof ScriptableObject) {
            ScriptRuntime.setObjectProtoAndParent((ScriptableObject) unwrapped, scope);
          }
          return unwrapped;
        }
      }
      return self;
    } catch (Exception ex) {
      throw Context.throwAsScriptRuntimeEx(ex);
    }
  }