org.jboss.jandex.package-info Maven / Gradle / Ivy
/**
* Jandex is a space efficient Java annotation indexer and offline reflection library.
*
* It supports the following capabilities:
*
*
* - Indexing all runtime visible Java annotations for a set of classes into a memory efficient representation.
* - Indexing the class hierarchy and interface implementation of a set classes.
* - Browsing and searching of declared methods on an indexed class.
* - Browsing and searching of declared fields on an indexed class.
* - Browsing of all generic type information on methods, fields, and classes.
* - Browsing and searching annotations, including Java 8 type annotations
* - Persisting an index into a custom storage efficient format.
* - Quick-loading of the storage efficient format
* - Compatibility with previous API and storage format versions
* - Execution via an API, a command line tool, and ant
*
*
* The starting point for most usages is to use {@link org.jboss.jandex.Indexer} on a set of class file streams
* to ultimately produce an {@link org.jboss.jandex.Index}. Alternatively, if a persisted Jandex index file is
* available, {@link org.jboss.jandex.IndexReader} can be used to load the {@link org.jboss.jandex.Index} directly
* from disk. The index files can be produced by using an {@link org.jboss.jandex.IndexWriter}, or by using
* the command line tool, which is available when using "-jar" on the Jandex jar, or by using the
* {@link org.jboss.jandex.JandexAntTask} with ant.
*
*
Browsing a Class
*
* The following example demonstrates indexing a class and browsing its methods:
*
*
* // Index java.util.Map
* Indexer indexer = new Indexer();
* // Normally a direct file is opened, but class-loader backed streams work as well.
* InputStream stream = getClass().getClassLoader().getResourceAsStream("java/util/Map.class");
* indexer.index(stream);
* Index index = indexer.complete();
*
* // Retrieve Map from the index and print its declared methods
* ClassInfo clazz = index.getClassByName(DotName.createSimple("java.util.Map"));
*
* for (MethodInfo method : clazz.methods()) {
* System.out.println(method);
* }
*
*
* Creating a Persisted Index
*
* The following example demonstrates indexing a class and persisting the index to disk. The resulting
* file can later be loaded scanning Java classes:
*
*
* // Index java.util.Map
* Indexer indexer = new Indexer();
* // Normally a direct file is opened, but class-loader backed streams work as well.
* InputStream stream = getClass().getClassLoader().getResourceAsStream("java/util/Map.class");
* indexer.index(stream);
* Index index = indexer.complete();
*
* FileOutputStream out = new FileOutputStream("/tmp/index.idx");
* IndexWriter writer = new IndexWriter(out);
*
* try {
* writer.write(index);
* } finally {
* safeClose(out);
* }
*
*
* Creating a Persisted Index Using the CLI
*
* The following example demonstrates indexing hibernate core, followed by the entire Java
* JDK using Jandex on the CLI:
*
*
* $ java -jar target/jandex-2.0.0.Alpha1.jar hibernate-core-4.0.0.Final.jar
* Wrote /Users/jason/devel/jandex/hibernate-core-4.0.0.Final-jar.idx in 0.9020 seconds
* (2722 classes, 20 annotations, 1696 instances, 621565 bytes)
*
* $ java -jar target/jandex-2.0.0.Alpha1.jar rt.jar
* Wrote /Users/jason/devel/jandex/rt-jar.idx in 4.2870 seconds
* (19831 classes, 41 annotations, 1699 instances, 4413790 bytes)
*
*
* The above summary output tells us that this version of hibernate has 2,722 classes, and those classes
* contained 1,696 annotation declarations, using 20 different annotation types. The resulting index
* is 606KB uncompressed, which is only 14% of the 4.1MB compressed jar size, or 4% of the uncompressed
* class file data. If the index is stored in the jar (using the -m option) it can be compressed an additional 47%,
* leading to a jar growth of only 8%
*
* Loading a Persisted Index
*
* The following example demonstrates loading the index from the previous example and using that
* index to print all methods on java.util.Map
:
*
*
* FileInputStream input = new FileInputStream("/tmp/index.idx");
* IndexReader reader = new IndexReader(input);
* try {
* index = reader.read();
* } finally {
* safeClose(input);
* }
*
* // Retrieve Map from the index and print its declared methods
* ClassInfo clazz = index.getClassByName(DotName.createSimple("java.util.Map"));
*
* for (MethodInfo method : clazz.methods()) {
* System.out.println(method);
* }
*
*
* Searching for an Annotation
*
* The following example demonstrates indexing the Thread and String classes, and searching for methods that
* have been marked with {@literal @}Deprecated:
*
*
* Indexer indexer = new Indexer();
* InputStream stream = getClass().getClassLoader().getResourceAsStream("java/lang/Thread.class");
* InputStream stream = getClass().getClassLoader().getResourceAsStream("java/lang/String.class");
* indexer.index(stream);
* Index index = indexer.complete();
* DotName deprecated = DotName.createSimple("java.lang.Deprecated");
* List<AnnotationInstance> annotations = index.getAnnotations(deprecated);
*
* for (AnnotationInstance annotation : annotations) {
* switch (annotation.target().kind()) {
* case METHOD:
* System.out.println(annotation.target());
* break;
* }
* }
*
*
* Analyzing Generics
*
* The following example demonstrates indexing the Collections class and printing the resolved bound
* on the List<T>
method parameter, which resolves to Comparable from the method type parameter.
*
*
The sort() method analyzed by the example is defined in source as:
*
* public static <T extends Comparable<? super T>> void sort(List<T> list)
*
*
* The example code, which prints "Comparable<? super T>"
, followed by "T"
is:
*
*
* Indexer indexer = new Indexer();
* InputStream stream = getClass().getClassLoader().getResourceAsStream("java/util/Collections.class");
* indexer.index(stream);
* Index index = indexer.complete();
*
* // Find method
* ClassInfo clazz = index.getClassByName(DotName.createSimple("java.util.Collections"));
* Type listType = Type.create(DotName.createSimple("java.util.List"), Type.Kind.CLASS);
* MethodInfo sort = clazz.method("sort", listType);
*
* Type t =
* sort.parameters().get(0).asParameterizedType() // List<T extends Comparable<? super T>>
* .arguments().get(0) // T extends Comparable<? super T>
* .asTypeVariable().bounds().get(0); // Comparable<? super T>
*
* System.out.println(t);
* System.out.println(t.asWildcardType().superBound()); // T
*
*
* Browsing Type Annotations
*
* Consider a complex nested generic structure which contains a @Label
annotation
*
*
* Map<Integer, List<@Label("Name") String>> names
*
*
* The following code will print "Name"
, the annotation value associated with the type:
*
*
* Indexer indexer = new Indexer();
* InputStream stream = new FileInputStream("/tmp/Test.class");
* indexer.index(stream);
* stream = new FileInputStream("/tmp/Test$Label.class");
* indexer.index(stream);
* Index index = indexer.complete();
*
* DotName test = DotName.createSimple("Test");
* FieldInfo field = index.getClassByName(test).field("names");
* System.out.println(
* field.type().asParameterizedType().arguments().get(1)
* .asParameterizedType().arguments().get(0)
* .annotations().get(0).value().asString()
* );
*
*
* Searching for Type Annotations
*
* A type annotation can also be located by searching for the annotation. The target for a found type annotation
* is represented as a TypeTarget
. The TypeTarget
provides a reference to the annotated
* type, as well as the enclosing target that contains the type. The target itself can be a method, a class, or a field.
* The usage on that target can be a number of places, including parameters, return types, type parameters,
* type arguments, class extends values, type bounds and receiver types. Subclasses of TypeTarget
provide
* the necessary information to locate the starting point of the usage.
*
*
Since the particular type use can occur at any depth, the relevant branch of the type tree constrained by the above
* starting point must be traversed to understand the context of the use.
*
*
Consider a complex nested generic structure which contains a @Label
annotation
*
*
* Map<Integer, List<@Label("Name") String>> names
*
*
* The following code locates a type annotation using a hardcoded path:
*
*
* Indexer indexer = new Indexer();
*
* InputStream stream = new FileInputStream("/tmp/Test.class");
* indexer.index(stream);
* stream = new FileInputStream("/tmp/Test$Label.class");
* indexer.index(stream);
*
* Index index = indexer.complete();
* List<AnnotationInstance> annotations = index.getAnnotations(DotName.createSimple("Test$Label"));
* for (AnnotationInstance annotation : annotations) {
* if (annotation.target().kind() == AnnotationTarget.Kind.TYPE) {
* TypeTarget typeTarget = annotation.target().asType();
* System.out.println("Type usage is located within: " + typeTarget.enclosingTarget());
* System.out.println("Usage type: " + typeTarget.usage());
* System.out.println("Target type:" + typeTarget.target());
* System.out.println("Equivalent? " + (typeTarget.enclosingTarget().asField().type()
* .asParameterizedType().arguments().get(1)
* .asParameterizedType().arguments().get(0)
* == typeTarget.target()));
* }
*
*
* The above code prints the following output:
*
*
* Type usage is located within: java.util.Map<java.lang.Integer,
* java.util.List<@Label(value = "Name") java.lang.String>>
* Test.names
* Usage type: EMPTY
* Target type:@Label(value = "Name") java.lang.String
* Equivalent? true
*
*
* @author Jason T. Greene
*/
package org.jboss.jandex;