Provide a way to get method parameter modifiers
kaqqao opened this issue · comments
There seems to be no way to get modifiers for method parameters, equivalent to java.lang.reflect.Parameter#getModifiers
.
In general, there seems to be no way to get info on parameters beyond the name and type...
I'm specifically trying to figure out if a parameter is implicit (java.lang.reflect.Parameter#isImplicit
) or synthetic (java.lang.reflect.Parameter#isSynthetic
).
I'm looking into this and I think I know why parameter flags are not exposed... They are almost never present in bytecode in the first place. They are only present in bytecode when javac
is invoked with the -parameters
option. This is also why the java.lang.reflect.Parameter
methods you mention are often unreliable.
I'm aware the -parameters
flag is required to keep names in the bytecode, but Javadoc for e.g. isImplicit()
mentions nothing about this info potentially not being available. For contrast, the docs for getName()
clearly state the name may be synthesized. My own experiments seem to corroborate that the modifiers and attributes are independent of the compilation options, but I really can't be sure.
Either way, I use -parameters
in my own projects, so support for that would still be welcome. But if really no useful info is available without -parameters
, I'd understand if you decided it isn't worth the effort.
At the moment, I'm leaning towards not exposing the parameter flags, but I need to investigate synthetic parameters more. I'll update this issue when done.
I have a nearly finished PR for handling mandated/synthetic parameters uniformly: #192. The final decision is for the most common parameter-related methods on MethodInfo
to pretend that mandated and synthetic parameters don't exist [1]. Interestingly, this is also how parameter names and annotations are indexed in bytecode. There will be a way to access the full list of types as present in the method descriptor, but it won't be possible to correlate those types with parameter names or annotations.
[1] This is actually surprisingly easy, because Jandex has already been doing that for methods that have the Signature
attribute in bytecode. So for methods that use type variables in their signature, this is already how Jandex behaves. Note that javac emits the Signature
attribute in other situations, too, e.g. for constructors of local/anonymous classes. In case the method doesn't have the Signature
attribute, Jandex will employ a simple heuristic that covers the most important cases: constructors of enums and non-static member classes. This won't work perfectly for constructors of local/anonymous classes compiled with ecj, but I believe that's acceptable. See also #45 (comment).
Hence, closing this.
BTW, here's a simple test class to verify whether isImplicit
and isSynthetic
work:
public class Test {
public enum MyEnum { INSTANCE }
public class Inner {
public Inner(int ignored) {
}
}
public static void main(String[] args) {
System.out.println(MyEnum.class.getDeclaredConstructors()[0]);
System.out.println(MyEnum.class.getDeclaredConstructors()[0].getParameters()[0]);
System.out.println(MyEnum.class.getDeclaredConstructors()[0].getParameters()[0].isImplicit());
System.out.println(MyEnum.class.getDeclaredConstructors()[0].getParameters()[0].isSynthetic());
Inner inner = new Test().new Inner(42);
System.out.println(inner.getClass().getDeclaredConstructors()[0]);
System.out.println(inner.getClass().getDeclaredConstructors()[0].getParameters()[0]);
System.out.println(inner.getClass().getDeclaredConstructors()[0].getParameters()[0].isImplicit());
System.out.println(inner.getClass().getDeclaredConstructors()[0].getParameters()[0].isSynthetic());
}
}
When compiled without -parameters
, this program prints:
private Test$MyEnum(java.lang.String,int)
java.lang.String arg0
false
false
public Test$Inner(Test,int)
Test arg0
false
false
When compiled with -parameters
, this program prints:
private Test$MyEnum(java.lang.String,int)
java.lang.String $enum$name
false
true
public Test$Inner(Test,int)
final Test this$0
true
false
So, really, isImplicit
and isSynthetic
only work when compiled with -parameters
.
For historical reference, JDK 21 fixes the bug that Parameter.isImplicit()
and isSynthetic()
only work when compiled with -parameters
: https://bugs.openjdk.org/browse/JDK-8292275