eScutable.hasrealParameterData()和参数。
这个问题是先前在保留参数/参数名称名称名称的问题名称在编译的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 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如 daniel fuchs 我们需要用
-parameters
标志编译代码。https://docs.oracle.com/ en/java/javase/18/docs/specs/man/javac.html
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