Summary
-------
javac does not accept some classfiles which contain valid RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, as specified in JVMS 4.7.18 and 4.7.19.
Problem
-------
The RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, as specified in JVMS 4.7.18 and 4.7.19 do not currently put any requirements on the number of entries in the attributes, or even the ordering of the entries. javac, however, only accepts classfiles where the number of entries in the attributes match its internal parameter count for the given method. javac rejects all other classfiles.
_Historical considerations:_
In JDK 8 and below, the attributes were specified as:
> The i'th entry in the table corresponds to the i'th formal parameter in the method descriptor (§4.3.3).
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.18
javac was not implementing the specification correctly in two aspects:
- when writing a classfile, when the `Signature` attribute was used for a method, it was only producing as many entries of these attributes as there were parameters in the Signature attribute
- when reading a classfile, if the `Signature` attribute was present for the method, javac expected the attribute to have exactly as many entries as there were parameters in the Signature attribute
In JDK 9, the wording for these attributes has been changed to:
> The i'th entry in the parameter_annotations table may, but is not required to, correspond to the i'th parameter descriptor in the method descriptor (§4.3.3).
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.18
This change made the classfile written by javac legal, but also made many other forms of the classfiles legal. javac was never adjusted to this change.
Solution
--------
Regardless of the number of entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, javac will never produce an error.
As the wording in the specification does not allow to reliably map the annotations to the parameters, it is proposed javac will use a number of heuristics to do the mapping. If none of these heuristics will yield a result, javac will ignore the attributes.
Note the heuristics below are intended to not change result for any classfiles which javac can read without errors currently. They only add new cases which are accepted by javac.
The proposal herein only concerns javac. Other parts of the JDK (notably the core reflection) may need to be adjusted separately, and are outside of the scope of this change.
Specification
-------------
The proposed heuristics are (if at least one of RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes is present):
- if both RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes are present, javac will ignore them both with a warning unless they have the same number of entries
- if, for the given method, there is the `Signature` attribute, and the number of entries in the attributes is the same as the number of parameters in the `Signature` attribute, the entries in the attributes will be used in order to fill the parameters from the `Signature` attribute,
- otherwise, if for the given method, there is no `Signature` attribute, if the method is a constructor, and the class is heuristically determined to be an inner class (the class is a non-static inner class and is determined to be neither an anonymous class, nor a local class), the first parameter is stripped, and if the number of parameters of this adjusted type is the same as the number of entries in the attributes, the entries in the attributes will be used in order to fill the parameters from this adjusted type,
- otherwise, if for the given method, there is no `Signature` attribute and if the method is not a constructor of a heuristically determined innerclass, and the number of entries in the attributes is the same as the number of parameters in the method's descriptor, the entries in the attributes will be used in order to fill the parameters from method's descritor,
- otherwise, if there is `MethodParameters` attribute for the method, and the number of non-synthetic and non-mandatory parameters as per the `MethodParameters` attribute is the same as the number of entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, the entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes will be used in order to fill the annotations on the non-synthetic and non-mandated parameters,
- otherwise, if there is `MethodParameters` attribute for the method, and the number parameters in the method's descritor is the same as the number of entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, the entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes that correspond to either synthetic and mandated parameters will be ignored, and the others will be used in order to fill the annotations on the non-synthetic and non-mandated parameters,
- otherwise, if there is no `MethodParameters`, the current method is a constructor for an enum types, there is no `Signature` attribute and the number of parameters in the method's descriptor minus 2 is the same as the number of entries in the the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, the entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes will be used in order to fill the annotations for the parameters starting from the 2nd parameter,
- otherwise, if the given classfile represents an (direct or indirect) local class, and there is no `Signature` attribute, and the number of parameters in the method's descriptor is greater than the number of entries in the the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes, the entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes will be used in order to fill the annotations for the parameters starting from the 1st parameter.
javac will never produce an error based on the number of entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes. javac will produce warnings if:
- the number of entries in the RuntimeVisibleParameterAnnotations and RuntimeInvisibleParameterAnnotations attributes differ
- none of the above heuristics applies