Hi Peter,
Yours is a more ambitious attempt to more fully resolve this issue. It
would likely nearly always work in practice, at least for
javac-generated class files.
However, at this stage of JDK 9, I'd be more comfortable with something
like the point fixes in my current patch, deferring a more complete
solution to JDK 10. At that point, I think a two-stage fall back would
be more complete: if the number of parameters differs, first try to see
if java.lang.reflect.Parameter.{isSynthetic, isImplicit} information is
available and if it is, use it accordingly. Otherwise, use the sort of
case analysis present in the patch.
FWIW, on the javax.lang.model side of reflective APIs, in JDK 9 we added
notions in the API to describe these sorts of differences in the
javax.lang.model.util.Elements.Origin enum:
http://download.java.net/java/jdk9/docs/api/javax/lang/model/util/Elements.Origin.html
and the Elements.getOrigin methods which return that type.
Thanks,
-Joe
On 5/20/2017 2:48 PM, Peter Levart wrote:
Hi Joe,
Thanks for explanation.
Regarding your patch. Take a look here:
http://cr.openjdk.java.net/~plevart/jdk9-dev/8074977_ConstructorParameterAnnotations/webrev.01/
I just want to point out that the logic could be centralized for
classical and type annotations. What do you think?
Regards, Peter
On 05/20/2017 11:38 PM, joe darcy wrote:
Hi Peter,
On 5/20/2017 11:00 AM, Peter Levart wrote:
Hi Joe,
So enum classes, anonymous classes and local classes don't have a
standard way of passing synthetic/implicit constructor parameters?
Right; there is no standardized or mandated way for compilers to do
that. Such details are intentionally outside of what the JLS specifies.
Since non-static member classes can be referred to and instances
instantiated from outside of the enclosing class, there has to be a
standardized linkage model in that case for separate compilation,
etc. and that is covered in the JLS. This isn't the case for local
and anonymous classes since there isn't a way to refer to such
classes from outside of their immediate declaration context. The
instances of such types can be returned of course and then it is
possible for people to getClass().getConstructors()... their way into
the issue.
Do various compilers do it differently than javac?
IIRC, ecj does compile enum classes differently than javac.
It's unfortunate but if # of parameter annotations arrays is less
than the # of parameters, Parameter.getAnnotations() may return
wrong annotations or throw IndexOutOfBoundException for enums,
anonymous and local classes. Can't we do anything for them? At least
for code compiled by javac?
For example, javac compiles enum classes so that they always prefix
constructor source parameters with a pair of (String name, int
ordinal, ...) and so do anonymous enum subclasses provided by enum
constants (i.e. clazz.isAnonymousClass() &&
clazz.getSuperclass().isEnum())
Non-static local classes are compiled so that constructor source
parameters are prefixed with a single parameter (OuterClass
outerInstance, ...), while any captured variables follow source
parameters
A wrinkle with local classes is that if they occur in a static
context, such as a static initializer block, there is no leading
outer instance parameter.
This is admittedly not a 100% solution to parameter mismatches and
annotations; however, it is an improvement over the current state of
affairs.
Ideally, the code for something like Parameters.getAnnotations could
do something like look at the synthetic bit and pair up natural
parameters with annotations if there was a mismatch in the number of
parameters and annotations. Unfortunately, the Parameters.isSynthetic
API wasn't introduced until JDK 8 and that information doesn't have
to be available.
Cheers,
-Joe
Static local classes are compiled so that constructor source
parameters come 1st, followed by any captured variables.
etc...
Regards, Peter
On 05/19/2017 11:31 PM, joe darcy wrote:
Hello,
Please review the webrev to fix
JDK-8074977: Constructor.getAnnotatedParameterTypes returns
wrong value
http://cr.openjdk.java.net/~darcy/8074977.3/
To condense a complicated situation, there are cases where the
number of parameters present for a constructor in source code and
the number of parameters present for that constructor in the class
file differ. One of those cases occurs for the constructor of a
non-static member class [1] where there is a leading parameter to
accept the outer this argument.
Bug JDK-8074977 reports on a situation where the type annotations
on constructor parameters are incorrectly reported. Essentially, an
off-by-one error is the cause since the annotation information is
stored with respect to the number of parameters present in the
source and an additional parameter is present at runtime.
An analogous situation exists for declaration annotations and
constructor parameters, declaration annotations being the
traditional flavor of annotations.
Type annotations and declaration annotations are read using
different APIs so require separate fixes to detect the additional
parameter and make the necessary adjustments in the returned
information.
The regression tests cover both the type annotation reading API and
the two ways of reading declaration annotations on parameters,
calling getParameterAnnotations on the constructor or call
getParameters on the constructor and then calling getAnnotations on
each parameter. The getParameters API was added in JDK 8.
Static member and non-static member classes are used as test cases,
as are constructors with and without generic type information.
Thanks,
-Joe
[1]
https://blogs.oracle.com/darcy/nested,-inner,-member,-and-top-level-classes