eScutable.hasrealParameterData()和参数。

发布于 2025-02-11 18:20:58 字数 5028 浏览 0 评论 0原文

这个问题是先前在保留参数/参数名称名称名称的问题名称在编译的Java类中,答案被接受,但解决方案似乎不起作用。

与临时构建的JDK 19(曝光executable.hasrealParameterData()),我将代码

public class Main {

  public static void main(String[] args) throws NoSuchMethodException {
    Method foo = Main.class.getMethod("foo", String.class, int.class);
    System.out.println(foo.hasRealParameterData());
  }

  public void foo(String parameter1, int parameter2) {}
}

进行编译,

% javac Main.java

然后我运行编译Java类,然后打印 false 进入控制台。这很好,因为分解main类看起来像是

public class Main {
  public Main() {}

  public static void main(String[] var0) throws NoSuchMethodException {
    Method var1 = Main.class.getMethod("foo", String.class, Integer.TYPE);
    System.out.println(var1.hasRealParameterData());
  }

  public void foo(String var1, int var2) {} // parameter names are not 'real'
}

参数名称是合成的。

这种行为是可以理解的。

然后,我将相同的Java源并通过我一次又一次地运行相同的代码重新编译该类

javac -g:vars Main.java

,然后将false打印到控制台。这使我感到困惑,因为现在编译的代码看起来不同:

public class Main {
  public Main() {}

  public static void main(String[] args) throws NoSuchMethodException {
    Method foo = Main.class.getMethod("foo", String.class, Integer.TYPE);
    System.out.println(foo.hasRealParameterData());
  }

  public void foo(String parameter1, int parameter2) {} // parameter names are 'real'
}

如果进行重新编译,则会使用普通-G flag(生成所有辅助数据)。

现在,让我们停止调用JDK的私有API,仅依靠可用的方法,例如parameter.isnamepresent()(此人调用executable.hasrealparameterdata() >在引擎盖下):

public static void main(String[] args) throws NoSuchMethodException {
  Method foo = Main.class.getMethod("foo", String.class, int.class);
  Parameter parameter1 = foo.getParameters()[0];
  Parameter parameter2 = foo.getParameters()[1];
  System.out.println(parameter1.isNamePresent());
  System.out.println(parameter2.isNamePresent());
}

public void foo(String parameter1, int parameter2) {}

再次,无论我如何编译源,此代码都会打印false false

这里的问题是executable.hasrealParameterData()调用本机方法getParameters0(

JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method))
{
  // method is a handle to a java.lang.reflect.Method object
  Method* method_ptr = jvm_get_method_common(method);
  methodHandle mh (THREAD, method_ptr);
  Handle reflected_method (THREAD, JNIHandles::resolve_non_null(method));
  const int num_params = mh->method_parameters_length();

  if (num_params < 0) {
    // A -1 return value from method_parameters_length means there is no
    // parameter data.  Return null to indicate this to the reflection
    // API.
    assert(num_params == -1, "num_params should be -1 if it is less than zero");
    return (jobjectArray)NULL;
  } else {
    // Otherwise, we return something up to reflection, even if it is
    // a zero-length array.  Why?  Because in some cases this can
    // trigger a MalformedParametersException.

    // make sure all the symbols are properly formatted
    for (int i = 0; i < num_params; i++) {
      MethodParametersElement* params = mh->method_parameters_start();
      int index = params[i].name_cp_index;
      constantPoolHandle cp(THREAD, mh->constants());
      bounds_check(cp, index, CHECK_NULL);

      if (0 != index && !mh->constants()->tag_at(index).is_utf8()) {
        THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
                    "Wrong type at constant pool index");
      }

    }

    objArrayOop result_oop = oopFactory::new_objArray(vmClasses::reflect_Parameter_klass(), num_params, CHECK_NULL);
    objArrayHandle result (THREAD, result_oop);

    for (int i = 0; i < num_params; i++) {
      MethodParametersElement* params = mh->method_parameters_start();
      // For a 0 index, give a NULL symbol
      Symbol* sym = 0 != params[i].name_cp_index ?
        mh->constants()->symbol_at(params[i].name_cp_index) : NULL;
      int flags = params[i].flags;
      oop param = Reflection::new_parameter(reflected_method, i, sym,
                                            flags, CHECK_NULL);
      result->obj_at_put(i, param);
    }
    return (jobjectArray)JNIHandles::make_local(THREAD, result());
  }
}
JVM_END

)如果没有参数数据。但是数据在编译类中存在。

所以我的问题是这是一个错误还是我做错了什么?

ps parameter.isnamepresent()即使我在常规而不是黑客jdk上运行它,也会意外地工作。

pps 在编译的代码中,我会看到“真实”参数名称,但是如果我在parameter.name.name arg0 arg0 >字段。

This question is kind of continuation of one previously asked in Preserving parameter/argument names in compiled java classes and the answer is accepted, but the solution seems to be not working.

With ad-hoc built JDK 19 (having exposed Executable.hasRealParameterData()) I take the code

public class Main {

  public static void main(String[] args) throws NoSuchMethodException {
    Method foo = Main.class.getMethod("foo", String.class, int.class);
    System.out.println(foo.hasRealParameterData());
  }

  public void foo(String parameter1, int parameter2) {}
}

and compile it with

% javac Main.java

Then I run compiled Java class and it prints false into console. This is fine because decompiled Main class looks like

public class Main {
  public Main() {}

  public static void main(String[] var0) throws NoSuchMethodException {
    Method var1 = Main.class.getMethod("foo", String.class, Integer.TYPE);
    System.out.println(var1.hasRealParameterData());
  }

  public void foo(String var1, int var2) {} // parameter names are not 'real'
}

i.e. parameter names are synthetic.

This behaviour is understandable.

Then I take the same Java sources and recompile the class with

javac -g:vars Main.java

I run the same code again and again it prints false to console. This puzzles me, because now the compiled code looks different:

public class Main {
  public Main() {}

  public static void main(String[] args) throws NoSuchMethodException {
    Method foo = Main.class.getMethod("foo", String.class, Integer.TYPE);
    System.out.println(foo.hasRealParameterData());
  }

  public void foo(String parameter1, int parameter2) {} // parameter names are 'real'
}

Same happens if for recompilation I use plain -g flag (generates all auxiliary data).

Now let's stop calling JDK's private API and rely only on the methods available out-of-the-box, e.g. Parameter.isNamePresent() (this one calls Executable.hasRealParameterData() under the hood):

public static void main(String[] args) throws NoSuchMethodException {
  Method foo = Main.class.getMethod("foo", String.class, int.class);
  Parameter parameter1 = foo.getParameters()[0];
  Parameter parameter2 = foo.getParameters()[1];
  System.out.println(parameter1.isNamePresent());
  System.out.println(parameter2.isNamePresent());
}

public void foo(String parameter1, int parameter2) {}

And again, no matter how I compile the sources, this code prints false false.

The problem here is that Executable.hasRealParameterData() calls native method getParameters0() implemented like:

JVM_ENTRY(jobjectArray, JVM_GetMethodParameters(JNIEnv *env, jobject method))
{
  // method is a handle to a java.lang.reflect.Method object
  Method* method_ptr = jvm_get_method_common(method);
  methodHandle mh (THREAD, method_ptr);
  Handle reflected_method (THREAD, JNIHandles::resolve_non_null(method));
  const int num_params = mh->method_parameters_length();

  if (num_params < 0) {
    // A -1 return value from method_parameters_length means there is no
    // parameter data.  Return null to indicate this to the reflection
    // API.
    assert(num_params == -1, "num_params should be -1 if it is less than zero");
    return (jobjectArray)NULL;
  } else {
    // Otherwise, we return something up to reflection, even if it is
    // a zero-length array.  Why?  Because in some cases this can
    // trigger a MalformedParametersException.

    // make sure all the symbols are properly formatted
    for (int i = 0; i < num_params; i++) {
      MethodParametersElement* params = mh->method_parameters_start();
      int index = params[i].name_cp_index;
      constantPoolHandle cp(THREAD, mh->constants());
      bounds_check(cp, index, CHECK_NULL);

      if (0 != index && !mh->constants()->tag_at(index).is_utf8()) {
        THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
                    "Wrong type at constant pool index");
      }

    }

    objArrayOop result_oop = oopFactory::new_objArray(vmClasses::reflect_Parameter_klass(), num_params, CHECK_NULL);
    objArrayHandle result (THREAD, result_oop);

    for (int i = 0; i < num_params; i++) {
      MethodParametersElement* params = mh->method_parameters_start();
      // For a 0 index, give a NULL symbol
      Symbol* sym = 0 != params[i].name_cp_index ?
        mh->constants()->symbol_at(params[i].name_cp_index) : NULL;
      int flags = params[i].flags;
      oop param = Reflection::new_parameter(reflected_method, i, sym,
                                            flags, CHECK_NULL);
      result->obj_at_put(i, param);
    }
    return (jobjectArray)JNIHandles::make_local(THREAD, result());
  }
}
JVM_END

From the code I see that null is returned only in case when there's no parameter data. But the data is there, in the compiled class.

So my question is whether this is a bug or am I doing something wrong?

P.S. Parameter.isNamePresent() works unexpectedly even when I run it on conventional, not hacked JDK.

P.P.S. In compiled code I see 'real' parameter names, but if I stop at debug point in IDEA parameter name is suddenly arg0 in Parameter.name field.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

你怎么这么可爱啊 2025-02-18 18:20:58

As it was pointed out by Daniel Fuchs we need to compile the code with -parameters flag.

https://docs.oracle.com/en/java/javase/18/docs/specs/man/javac.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文