Class ClassFileParameterAnnotations

java.lang.Object
io.micronaut.scala.processing.visitor.ClassFileParameterAnnotations

public final class ClassFileParameterAnnotations extends Object
The annotations on the parameters of a Java class file's methods.

The Scala compiler reads a Java class from its class file into the same symbols a Scala class has, and that reading is what the rest of the model is built from. It leaves one thing out: dotty's class-file parser does not read RuntimeVisibleParameterAnnotations or its invisible counterpart at all -- a documented TODO -- and parameter annotations are where Micronaut looks most. @Nullable decides whether an argument may be absent, @Body and @QueryValue decide where it comes from, and @Id on a repository method's parameter decides what it means.

This reads exactly that, from the bytes the compiler already has for the class, with the JDK's own class-file API. Nothing is loaded: reading bytes has no static initialiser to run and no classloader to choose, which is what the reflective reading it replaces got wrong whenever the plugin's classloader and the application's disagreed.

Type annotations are read as well, where they sit on a parameter's own type, a return type or a field's type. Nullability in Java has moved there: jspecify's @Nullable is TYPE_USE only, so body(@Nullable T body) records nothing in the parameter annotations and everything in the type annotations, and javac's model reports it on the parameter regardless. Annotations deeper in a type -- on a type argument -- are left where they are.

The values come out as plain data -- constants, names, and the records below -- and are turned into the model's own annotation data by the extractor, which is where the annotation types are resolved.

  • Method Details

    • parse

      public static ClassFileParameterAnnotations parse(byte[] bytes)
      Reads a class file.
      Parameters:
      bytes - The class file
      Returns:
      Its parameter annotations
    • forMethod

      public ClassFileParameterAnnotations.MethodAnnotations forMethod(String name, List<String> erasedParameterTypes)
      The annotations of a method the compiler did not read: on its parameters, and on its return type and parameter types.

      The method is found by name and by the erased types of its parameters, which is what a JVM descriptor holds. An overload set is disambiguated that way; a single method of the name and arity is taken as is, so a mismatch in how an erasure is spelled cannot lose the annotations of an unambiguous method.

      A constructor of an inner class takes the enclosing instance as a leading parameter the language does not show, and the compiler's model of it does not either. When no constructor matches as declared, one whose descriptor has exactly that one extra leading parameter is accepted. Whether its annotation attributes count that parameter is the compiler's choice -- the JVM specification leaves it open, javac counts the parameters written in the source and other compilers have counted the descriptor's -- so each attribute is read by what it holds: one entry per written parameter is aligned as it is, and one that runs past the written parameters is aligned from the descriptor.

      Parameters:
      name - The method name, <init> for a constructor
      erasedParameterTypes - The erased parameter types, as binary names
      Returns:
      The annotations, ClassFileParameterAnnotations.MethodAnnotations.NONE when the method is not found
    • privateFields

      The private fields of the class, which the compiler does not enter at all.

      dotty's class-file parser skips every private member of a Java class -- a Scala program cannot refer to one, so the compiler has no use for it. Micronaut does: an @Inject field or a @PostConstruct method in a library's base class may well be private, and the Java model shows both. They are read from the class file instead, with their generic signatures, so the model can build the same types for them it builds for everything else.

      Returns:
      The private fields, in class-file order
    • privateMethods

      The private methods of the class, which the compiler does not enter at all; see privateFields(). Constructors, bridges and synthetics are not included.
      Returns:
      The private methods, in class-file order
    • annotationDefaults

      public Map<String,Object> annotationDefaults()
      The default value of each member of an annotation type, from its AnnotationDefault attributes. The compiler records that a member has a default and discards the value; the value is what a use of the annotation that omits the member means.
      Returns:
      The defaults by member name, as ClassFileParameterAnnotations.Annotation values are represented
    • forField

      The type annotations on a field's type, which the compiler does not read.
      Parameters:
      name - The field name
      Returns:
      The annotations, empty when there are none or the field is not found