Class Indexer


  • public final class Indexer
    extends java.lang.Object
    Analyzes and indexes the annotation and key structural information of a set of classes. The indexer will purposefully skip any class that is not Java 5 or later. It will also do a basic/quick structural scan on any class it determines does not have annotations.

    The Indexer operates on input streams that point to class file data. Input streams do not need to be buffered, as the indexer already does this. There is also no limit to the number of class file streams the indexer can process, other than available memory.

    The Indexer attempts to minimize the final memory state of the index, but to do this it must maintain additional in-process state (intern tables etc) until the index is complete.

    Numerous optimizations are taken during indexing to attempt to minimize the CPU and I/O cost, however, the Java class file format was not designed for partial searching, which ultimately limits the efficiency of processing them.

    Thread-Safety This class is not thread-safe can not be shared between threads. The index it produces however is thread-safe.

    • Field Detail

      • CONSTANT_INTERFACEMETHODREF

        private static final int CONSTANT_INTERFACEMETHODREF
        See Also:
        Constant Field Values
      • CONSTANT_INVOKEDYNAMIC

        private static final int CONSTANT_INVOKEDYNAMIC
        See Also:
        Constant Field Values
      • RUNTIME_ANNOTATIONS

        private static final byte[] RUNTIME_ANNOTATIONS
      • RUNTIME_PARAM_ANNOTATIONS

        private static final byte[] RUNTIME_PARAM_ANNOTATIONS
      • RUNTIME_TYPE_ANNOTATIONS

        private static final byte[] RUNTIME_TYPE_ANNOTATIONS
      • ANNOTATION_DEFAULT

        private static final byte[] ANNOTATION_DEFAULT
      • SIGNATURE

        private static final byte[] SIGNATURE
      • EXCEPTIONS

        private static final byte[] EXCEPTIONS
      • INNER_CLASSES

        private static final byte[] INNER_CLASSES
      • ENCLOSING_METHOD

        private static final byte[] ENCLOSING_METHOD
      • METHOD_PARAMETERS

        private static final byte[] METHOD_PARAMETERS
      • LOCAL_VARIABLE_TABLE

        private static final byte[] LOCAL_VARIABLE_TABLE
      • CODE

        private static final byte[] CODE
      • MODULE

        private static final byte[] MODULE
      • MODULE_PACKAGES

        private static final byte[] MODULE_PACKAGES
      • MODULE_MAIN_CLASS

        private static final byte[] MODULE_MAIN_CLASS
      • RECORD

        private static final byte[] RECORD
      • RUNTIME_INVISIBLE_ANNOTATIONS

        private static final byte[] RUNTIME_INVISIBLE_ANNOTATIONS
      • RUNTIME_INVISIBLE_PARAM_ANNOTATIONS

        private static final byte[] RUNTIME_INVISIBLE_PARAM_ANNOTATIONS
      • RUNTIME_INVISIBLE_TYPE_ANNOTATIONS

        private static final byte[] RUNTIME_INVISIBLE_TYPE_ANNOTATIONS
      • PERMITTED_SUBCLASSES

        private static final byte[] PERMITTED_SUBCLASSES
      • RUNTIME_ANNOTATIONS_LEN

        private static final int RUNTIME_ANNOTATIONS_LEN
      • RUNTIME_PARAM_ANNOTATIONS_LEN

        private static final int RUNTIME_PARAM_ANNOTATIONS_LEN
      • RUNTIME_TYPE_ANNOTATIONS_LEN

        private static final int RUNTIME_TYPE_ANNOTATIONS_LEN
      • ANNOTATION_DEFAULT_LEN

        private static final int ANNOTATION_DEFAULT_LEN
      • SIGNATURE_LEN

        private static final int SIGNATURE_LEN
      • EXCEPTIONS_LEN

        private static final int EXCEPTIONS_LEN
      • INNER_CLASSES_LEN

        private static final int INNER_CLASSES_LEN
      • ENCLOSING_METHOD_LEN

        private static final int ENCLOSING_METHOD_LEN
      • METHOD_PARAMETERS_LEN

        private static final int METHOD_PARAMETERS_LEN
      • LOCAL_VARIABLE_TABLE_LEN

        private static final int LOCAL_VARIABLE_TABLE_LEN
      • CODE_LEN

        private static final int CODE_LEN
      • MODULE_LEN

        private static final int MODULE_LEN
      • MODULE_PACKAGES_LEN

        private static final int MODULE_PACKAGES_LEN
      • MODULE_MAIN_CLASS_LEN

        private static final int MODULE_MAIN_CLASS_LEN
      • RECORD_LEN

        private static final int RECORD_LEN
      • RUNTIME_INVISIBLE_ANNOTATIONS_LEN

        private static final int RUNTIME_INVISIBLE_ANNOTATIONS_LEN
      • RUNTIME_INVISIBLE_PARAM_ANNOTATIONS_LEN

        private static final int RUNTIME_INVISIBLE_PARAM_ANNOTATIONS_LEN
      • RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_LEN

        private static final int RUNTIME_INVISIBLE_TYPE_ANNOTATIONS_LEN
      • PERMITTED_SUBCLASSES_LEN

        private static final int PERMITTED_SUBCLASSES_LEN
      • HAS_RUNTIME_ANNOTATION

        private static final int HAS_RUNTIME_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_RUNTIME_PARAM_ANNOTATION

        private static final int HAS_RUNTIME_PARAM_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_RUNTIME_TYPE_ANNOTATION

        private static final int HAS_RUNTIME_TYPE_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_ANNOTATION_DEFAULT

        private static final int HAS_ANNOTATION_DEFAULT
        See Also:
        Constant Field Values
      • HAS_LOCAL_VARIABLE_TABLE

        private static final int HAS_LOCAL_VARIABLE_TABLE
        See Also:
        Constant Field Values
      • HAS_RUNTIME_INVISIBLE_ANNOTATION

        private static final int HAS_RUNTIME_INVISIBLE_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_RUNTIME_INVISIBLE_PARAM_ANNOTATION

        private static final int HAS_RUNTIME_INVISIBLE_PARAM_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_RUNTIME_INVISIBLE_TYPE_ANNOTATION

        private static final int HAS_RUNTIME_INVISIBLE_TYPE_ANNOTATION
        See Also:
        Constant Field Values
      • HAS_PERMITTED_SUBCLASSES

        private static final int HAS_PERMITTED_SUBCLASSES
        See Also:
        Constant Field Values
      • constantPoolSize

        private int constantPoolSize
      • constantPool

        private byte[] constantPool
      • constantPoolOffsets

        private int[] constantPoolOffsets
      • constantPoolAnnoAttrributes

        private byte[] constantPoolAnnoAttrributes
      • currentClass

        private ClassInfo currentClass
      • signaturePresent

        private java.util.IdentityHashMap<AnnotationTarget,​java.lang.Object> signaturePresent
      • signatures

        private java.util.List<java.lang.Object> signatures
      • classSignatureIndex

        private int classSignatureIndex
      • methods

        private java.util.List<MethodInfo> methods
      • fields

        private java.util.List<FieldInfo> fields
      • modulePackages

        private java.util.List<DotName> modulePackages
      • moduleMainClass

        private DotName moduleMainClass
      • subclasses

        private java.util.Map<DotName,​java.util.List<ClassInfo>> subclasses
      • subinterfaces

        private java.util.Map<DotName,​java.util.List<ClassInfo>> subinterfaces
      • implementors

        private java.util.Map<DotName,​java.util.List<ClassInfo>> implementors
    • Constructor Detail

      • Indexer

        public Indexer()
    • Method Detail

      • match

        private static boolean match​(byte[] target,
                                     int offset,
                                     byte[] expected)
      • sizeToFit

        private static byte[] sizeToFit​(byte[] buf,
                                        int needed,
                                        int offset,
                                        int remainingEntries)
      • newLength

        private static int newLength​(int oldLength,
                                     int minGrowth,
                                     int prefGrowth)
      • minLength

        private static int minLength​(int oldLength,
                                     int minGrowth)
      • skipFully

        private static void skipFully​(java.io.InputStream s,
                                      long n)
                               throws java.io.IOException
        Throws:
        java.io.IOException
      • initIndexMaps

        private void initIndexMaps()
      • initClassFields

        private void initClassFields()
      • processMethodInfo

        private void processMethodInfo​(java.io.DataInputStream data)
                                throws java.io.IOException
        Throws:
        java.io.IOException
      • processFieldInfo

        private void processFieldInfo​(java.io.DataInputStream data)
                               throws java.io.IOException
        Throws:
        java.io.IOException
      • processRecordComponents

        private void processRecordComponents​(java.io.DataInputStream data)
                                      throws java.io.IOException
        Throws:
        java.io.IOException
      • processPermittedSubclasses

        private void processPermittedSubclasses​(java.io.DataInputStream data,
                                                ClassInfo target)
                                         throws java.io.IOException
        Throws:
        java.io.IOException
      • processAttributes

        private void processAttributes​(java.io.DataInputStream data,
                                       AnnotationTarget target)
                                throws java.io.IOException
        Throws:
        java.io.IOException
      • processModule

        private void processModule​(java.io.DataInputStream data,
                                   ClassInfo target)
                            throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleRequires

        private java.util.List<ModuleInfo.RequiredModuleInfo> processModuleRequires​(java.io.DataInputStream data)
                                                                             throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleExports

        private java.util.List<ModuleInfo.ExportedPackageInfo> processModuleExports​(java.io.DataInputStream data)
                                                                             throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleOpens

        private java.util.List<ModuleInfo.OpenedPackageInfo> processModuleOpens​(java.io.DataInputStream data)
                                                                         throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleUses

        private java.util.List<DotName> processModuleUses​(java.io.DataInputStream data)
                                                   throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleProvides

        private java.util.List<ModuleInfo.ProvidedServiceInfo> processModuleProvides​(java.io.DataInputStream data)
                                                                              throws java.io.IOException
        Throws:
        java.io.IOException
      • processModulePackages

        private void processModulePackages​(java.io.DataInputStream data,
                                           ClassInfo target)
                                    throws java.io.IOException
        Throws:
        java.io.IOException
      • processModuleMainClass

        private void processModuleMainClass​(java.io.DataInputStream data,
                                            ClassInfo target)
                                     throws java.io.IOException
        Throws:
        java.io.IOException
      • processCode

        private void processCode​(java.io.DataInputStream data,
                                 MethodInfo target)
                          throws java.io.IOException
        Throws:
        java.io.IOException
      • processAnnotationDefault

        private void processAnnotationDefault​(java.io.DataInputStream data,
                                              MethodInfo target)
                                       throws java.io.IOException
        Throws:
        java.io.IOException
      • processAnnotations

        private void processAnnotations​(java.io.DataInputStream data,
                                        AnnotationTarget target,
                                        boolean visible)
                                 throws java.io.IOException
        Throws:
        java.io.IOException
      • processInnerClasses

        private void processInnerClasses​(java.io.DataInputStream data,
                                         ClassInfo target)
                                  throws java.io.IOException
        Throws:
        java.io.IOException
      • processMethodParameters

        private void processMethodParameters​(java.io.DataInputStream data,
                                             MethodInfo target)
                                      throws java.io.IOException
        Throws:
        java.io.IOException
      • processLocalVariableTable

        private void processLocalVariableTable​(java.io.DataInputStream data,
                                               MethodInfo target)
                                        throws java.io.IOException
        Throws:
        java.io.IOException
      • processEnclosingMethod

        private void processEnclosingMethod​(java.io.DataInputStream data,
                                            ClassInfo target)
                                     throws java.io.IOException
        Throws:
        java.io.IOException
      • processTypeAnnotations

        private void processTypeAnnotations​(java.io.DataInputStream data,
                                            AnnotationTarget target,
                                            boolean visible)
                                     throws java.io.IOException
        Throws:
        java.io.IOException
      • processTypeAnnotation

        private Indexer.TypeAnnotationState processTypeAnnotation​(java.io.DataInputStream data,
                                                                  AnnotationTarget target,
                                                                  boolean visible)
                                                           throws java.io.IOException
        Throws:
        java.io.IOException
      • adjustMethodParameters

        private void adjustMethodParameters()
      • isInnerConstructor

        private boolean isInnerConstructor​(MethodInfo method)
      • isEnumConstructor

        private static boolean isEnumConstructor​(MethodInfo method)
      • resolveTypeAnnotations

        private void resolveTypeAnnotations()
      • resolveUsers

        private void resolveUsers()
                           throws java.io.IOException
        Throws:
        java.io.IOException
      • recordUsedType

        private void recordUsedType​(Type type)
      • recordUsedClass

        private void recordUsedClass​(DotName usedClass)
      • updateTypeTargets

        private void updateTypeTargets()
      • setTypeParameters

        private static void setTypeParameters​(AnnotationTarget target,
                                              Type[] typeParameters)
      • isBridge

        private boolean isBridge​(MethodInfo methodInfo)
      • outermostAnnotableTypeName

        private DotName outermostAnnotableTypeName​(Type type)
        Returns the name of the outermost type that encloses given type and on which type annotations are admissible. This is either the nearest enclosing static nested class, or the enclosing top-level class. If type is not a nested type, returs its name.

        This could easily be implemented by calling buildClassesQueue(Type) and looking at the first element. The only difference is that the present implementation doesn't allocate and is probably a little faster.

      • buildClassesQueue

        private java.util.ArrayDeque<Indexer.InnerClassInfo> buildClassesQueue​(Type type)
        Returns a list of Indexer.InnerClassInfos representing types enclosing given type. Only types on which type annotations are admissible are present in the result. That is, the first element of the list represents the outermost type on which type annotations are admissible, and the last element of the list is an InnerClassInfo representing type itself. Returns an empty list if type is not a nested type.
      • buildOwnerMap

        private java.util.Map<DotName,​Type> buildOwnerMap​(Type type)
      • skipTargetPath

        private void skipTargetPath​(java.io.DataInputStream data)
                             throws java.io.IOException
        Throws:
        java.io.IOException
      • processExceptions

        private void processExceptions​(java.io.DataInputStream data,
                                       MethodInfo target)
                                throws java.io.IOException
        Throws:
        java.io.IOException
      • processSignature

        private void processSignature​(java.io.DataInputStream data,
                                      AnnotationTarget target)
                               throws java.io.IOException
        Throws:
        java.io.IOException
      • applySignatures

        private void applySignatures()
      • parseClassSignature

        private void parseClassSignature​(java.lang.String signature,
                                         ClassInfo clazz)
      • parseFieldSignature

        private void parseFieldSignature​(java.lang.String signature,
                                         FieldInfo field)
      • parseMethodSignature

        private void parseMethodSignature​(java.lang.String signature,
                                          MethodInfo method)
      • parseRecordComponentSignature

        private void parseRecordComponentSignature​(java.lang.String signature,
                                                   RecordComponentInfo recordComponent)
      • processAnnotation

        private AnnotationInstance processAnnotation​(java.io.DataInputStream data,
                                                     AnnotationTarget target,
                                                     boolean visible)
                                              throws java.io.IOException
        Throws:
        java.io.IOException
      • intern

        private java.lang.String intern​(java.lang.String string)
      • intern

        private byte[] intern​(byte[] bytes)
      • intern

        private Type intern​(Type type)
      • intern

        private Type[] intern​(Type[] type)
      • processAnnotationElementValue

        private AnnotationValue processAnnotationElementValue​(java.lang.String name,
                                                              java.io.DataInputStream data)
                                                       throws java.io.IOException
        Throws:
        java.io.IOException
      • processClassInfo

        private void processClassInfo​(java.io.DataInputStream data)
                               throws java.io.IOException
        Throws:
        java.io.IOException
      • addSubclass

        private void addSubclass​(DotName superName,
                                 ClassInfo currentClass)
      • addSubinterface

        private void addSubinterface​(DotName superName,
                                     ClassInfo currentClass)
      • addImplementor

        private void addImplementor​(DotName interfaceName,
                                    ClassInfo currentClass)
      • isJDK11OrNewer

        private boolean isJDK11OrNewer​(java.io.DataInputStream stream)
                                throws java.io.IOException
        Throws:
        java.io.IOException
      • verifyMagic

        private void verifyMagic​(java.io.DataInputStream stream)
                          throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeClassEntry

        private DotName decodeClassEntry​(int index)
                                  throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeModuleEntry

        private DotName decodeModuleEntry​(int index)
                                   throws java.io.IOException
        Throws:
        java.io.IOException
      • decodePackageEntry

        private DotName decodePackageEntry​(int index)
                                    throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeDotNameEntry

        private DotName decodeDotNameEntry​(int index,
                                           int constantType,
                                           java.lang.String typeName,
                                           char delim)
                                    throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeOptionalUtf8Entry

        private java.lang.String decodeOptionalUtf8Entry​(int index)
                                                  throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeUtf8Entry

        private java.lang.String decodeUtf8Entry​(int index)
                                          throws java.io.IOException
        Throws:
        java.io.IOException
      • decodeUtf8EntryAsBytes

        private byte[] decodeUtf8EntryAsBytes​(int index)
      • decodeNameAndTypeEntry

        private Indexer.NameAndType decodeNameAndTypeEntry​(int index)
                                                    throws java.io.IOException
        Throws:
        java.io.IOException
      • bitsToInt

        private int bitsToInt​(byte[] pool,
                              int pos)
      • bitsToLong

        private long bitsToLong​(byte[] pool,
                                int pos)
      • decodeIntegerEntry

        private int decodeIntegerEntry​(int index)
      • decodeLongEntry

        private long decodeLongEntry​(int index)
      • decodeFloatEntry

        private float decodeFloatEntry​(int index)
      • decodeDoubleEntry

        private double decodeDoubleEntry​(int index)
      • convertClassFieldDescriptor

        private static java.lang.String convertClassFieldDescriptor​(java.lang.String descriptor)
      • parseType

        private Type parseType​(java.lang.String descriptor)
      • processConstantPool

        private boolean processConstantPool​(java.io.DataInputStream stream)
                                     throws java.io.IOException
        Throws:
        java.io.IOException
      • indexClass

        public void indexClass​(java.lang.Class<?> clazz)
                        throws java.io.IOException
        Analyze and index the class file data of given clazz. Each call adds information to the final complete index.
        Parameters:
        clazz - a previously-loaded class
        Throws:
        java.io.IOException - if the class file data is corrupt or the underlying stream fails
        java.lang.IllegalArgumentException - if clazz is null
      • indexClass$$bridge

        public ClassInfo indexClass$$bridge​(java.lang.Class<?> clazz)
                                     throws java.io.IOException
        Throws:
        java.io.IOException
      • index

        public void index​(java.io.InputStream stream)
                   throws java.io.IOException
        Analyze and index the class file data present in given input stream. Each call adds information to the final complete index. Closing the input stream is the caller's responsibility.
        Parameters:
        stream - the class bytecode to index, must not be null
        Throws:
        java.io.IOException - if the class file data is corrupt or the stream fails
        java.lang.IllegalArgumentException - if stream is null
      • index$$bridge

        public ClassInfo index$$bridge​(java.io.InputStream stream)
                                throws java.io.IOException
        Throws:
        java.io.IOException
      • indexWithSummary

        public ClassSummary indexWithSummary​(java.io.InputStream stream)
                                      throws java.io.IOException
        Analyze and index the class file data present in given input stream. Each call adds information to the final complete index. Closing the input stream is the caller's responsibility.

        For reporting progress in batch indexers, this variant of index returns a summary of the just-indexed class.

        Parameters:
        stream - the class bytecode to index, must not be null
        Returns:
        a summary of the just-indexed class
        Throws:
        java.io.IOException - if the class file data is corrupt or the stream fails
        java.lang.IllegalArgumentException - if stream is null
      • complete

        public Index complete()
        Completes, finalizes, and returns the index after zero or more calls to index(). Future calls to index() will result in a new index.
        Returns:
        the master index for all scanned class streams
      • propagateTypeParameterBounds

        private void propagateTypeParameterBounds()
      • propagateTypeParameterBounds

        private void propagateTypeParameterBounds​(AnnotationTarget target,
                                                  java.util.Deque<TypeVariable> sharedTypeVarStack)
      • propagateOneTypeParameterBound

        private Type propagateOneTypeParameterBound​(Type type,
                                                    Type[] allTypeParams,
                                                    AnnotationTarget target)
      • deepCopyTypeIfNeeded

        private Type deepCopyTypeIfNeeded​(Type type)
        When type contains no type variable references, returns type. When type does contain type variable references, returns a deep copy with each reference replaced by a new one. In that case, the newly created references must be patched by the caller.

        When called from outside, type must be a type variable.

      • patchTypeVariableReferences

        private void patchTypeVariableReferences​(Type type,
                                                 java.util.Deque<TypeVariable> typeVarStack,
                                                 AnnotationTarget parametricEncloser)
        Patches all type variable references contained in given type. The typeVarStack is used to track enclosing type variables when traversing the structure of the type; when called from outside, it must be empty and must not be used anywhere else. The parametricEncloser is the type's nearest enclosing annotation target that may have type parameters, that is, the nearest enclosing method or class.
      • findTypeParameter

        private TypeVariable findTypeParameter​(Type[] typeParameters,
                                               java.lang.String identifier)
        Finds and returns a type variable with given identifier among given typeParameters. Returns null when none exists.
      • resolveTypeParameter

        private TypeVariable resolveTypeParameter​(AnnotationTarget target,
                                                  java.lang.String identifier)
        Resolves a given type variable identifier against given parametric target (either a method or a class). That is, if the target has a type parameter with matching identifier, returns it; otherwise, resolves identifier against target's nearest enclosing method or class. Returns null if the identifier can't be resolved.
      • getTypeVariableIdentifier

        private java.lang.String getTypeVariableIdentifier​(Type typeVariable)
      • propagateTypeVariables

        private void propagateTypeVariables()
      • retargetTypeAnnotations

        private void retargetTypeAnnotations​(AnnotationTarget parametricEncloser,
                                             Type oldType,
                                             Type newType)