Skip to content
forked from atteo/classindex

Index Kotlin classes at compile time as if they were statically referenced.

License

Notifications You must be signed in to change notification settings

matfax/klassindex

Repository files navigation

KlassIndex

Build Status Codacy Badge GitHub License GitHub last commit

About

KlassIndex is the younger Kotlin brother of atteo/classindex. However, it differs from ClassIndex in various aspects.

Aspects ClassIndex KlassIndex
Language Java Kotlin
Supported Classes Any Java class Any Kotlin class
Supported Build Tools Maven and outdated Gradle versions7 Any Gradle version
Supported Scopes Annotations, Subclasses, Packages Annotations, Subclasses6
Service Loader Support Yes No, superfluous8
JaxB Index Yes No
Stores Documentation Yes No
IDE Support Eclipse, Netbeans, Jetbrains (limited)3 Full Jetbrains support
Android Support Limited2 Yes
Runtime Performance Great Even Greater1
Filtering Support Limited Complete functional support4
Extension Support Yes Theoretically, TBD
Jar Shading Support Yes Maybe
Compile Time Safety Limited5 Complete
Class Loader Required Yes No
License Apache 2.0 Apache 2.0

Explanation

1.ClassIndex stores the qualified names of the classes to load at run time in the jar's resources. The resource parsing and class loading comes with a cost. In contrast, KlassIndex statically compiles the references. That means resource and classloading are not necessary. Excluded, however, are use cases where you have tons of classes and want only to load few of them, ClassIndex might show a better performance.

2.ClassIndex depends on resource and class loading. In use cases in Android where no context is available or a different class loader is to be used, ClassIndex will fail. KlassIndex compiles the references statically to enable full support.

3.New IntelliJ and Android Studio versions require newer versions of Gradle to provide full support.

4.KlassIndex provides all functional methods from Kotlin's Iterable, not just filters.

5.ClassIndex uses workarounds to detect if classes are valid and still existent. KlassIndex, however uses statically compiled generated classes so that the compiler can check the validity.

6.Kotlin does not (yet?) have such a concept such as Java's package files. Thus, package indexing has been removed to be consistent with the Kotlin.

7.ClassIndex does not provide separate dependency modules for annotation processing and compilation as required by newer Gradle versions (i.e., deprecated in Gradle 4.x, to be dropped in Gradle 5.x). KlassIndex provides a spearate annotation processor to be used with Gradle's kotlin-kapt.

8.The only use case in which a service loader is to be preferred over statical compilation are plugin-based systems.

Methods

-the list of classes annotated by a given annotation getAnnotated() -the list of classes implementing a given interface getSubclasses()

Advantages

KlassIndex -is faster than reading a file, it is not impacted by the usual performance penalty of the classpath scanning -is not depending on a class loader -is leight-weight and simple -supports incremental compilation in IntelliJ and Android Studio

How to use it?

Add Dependency

Gradle

-Add repository

allprojects {
	repositories {
		maven { url 'https://jitpack.io' }
	}
}

-Add dependencies

compile 'com.github.matfax.klassindex:library:4.+'
kapt 'com.github.matfax.klassindex:processor:4.+'

Gradle in Kotlin DSL

-Add repository

allprojects {
    repositories {
    	maven("https://jitpack.io")
	}
}

-Add dependencies

compile("com.github.matfax.klassindex:library:4.+")
kapt("com.github.matfax.klassindex:processor:4.+")

Others

For others, check: Jitpack

Annotations

1.Annotate your annotation with @IndexAnnotated

@IndexAnnotated
annotation class YourAnnotation

1.Retrieve a list of annotated classes at run-time

KlassIndex.getAnnotated(Component::class)

Subclasses

1.Annotate your superclass with @IndexSubclasses

@IndexSubclasses
interface YourSuperclass

1.Retrieve a list of annotated classes at run-time

KlassIndex.getSubclasses(YourSuperclass::class)

Index Processing

Filtering allows you to select only classes with desired characteristics. Here are some basic samples:

*Selecting only top-level classes

KlassIndex.getAnnotated(SomeAnnotation.class).topLevel()

*Selecting only classes which are top level and public at the same time

KlassIndex.getAnnotated(SomeAnnotation.class).topLevel().withModifiers(Modifier.PUBLIC)

*Selecting only the object instances from singleton classes that are annotated with an additional annotation.

KlassIndex.getAnnotated(SomeAnnotation.class).annotatedWith(SecondAnnotation::class).objects()

For more examples, check the test file.

How it works?

Annotation Index Processor

KlassIndex indexes your classes at compile time by providing the implementation of the standard annotation processor. The index is then used by kapt utilizing kotlinpoet to generate new Kotlin source files that hold the static references to the indexed classes. The compiler uses the source files as if they were manually written.

Run Time Library

KlassIndex provides a library to load the statically compiled index from the generated classes and to process them.

Why KlassIndex?

Speed

Traditional classpath scanning is a very slow process. Replacing it with compile-time indexing speeds Java applications bootstrap considerably.

Here are the results of the benchmark comparing ClassIndex with various scanning solutions.

Library Application startup time
None - hardcoded list 0:00.18
Scannotation 0:05.11
Reflections 0:05.37
Reflections Maven plugin 0:00.52
Corn 0:24.60
ClassIndex 0:00.18
KlassIndex TBD

Notes: benchmark was performed on Intel i5-2520M CPU @ 2.50GHz, classpath size was set to 121MB.