Current features:
- Automatic way to hide symbols, with the automatic hiding of
internal
symbols ; - Manual way to hide symbols, by using two different annotations to hide symbols from either Kotlin or Java sources ;
- Possibility to use the
package-private
visibility thanks to ann annotation ; - Generation of private constructors for top-level classes .
Both compiler plugin and annotations are added to your project's dependencies in the same unique way, as shown below :
Click to expand
Using Kotlin DSL:
plugins {
id("com.zwendo.restrikt") version "4.0.0"
}
Using Groovy DSL:
plugins {
id 'com.zwendo.restrikt' version '4.0.0'
}
Click to expand
Using Kotlin DSL:
buildscript {
repositories {
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
dependencies {
classpath("gradle.plugin.com.restrikt:restrikt:4.0.0")
}
}
apply(plugin = "com.zwendo.restrikt")
Using Groovy DSL:
buildscript {
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath 'gradle.plugin.com.restrikt:restrikt:4.0.0'
}
}
apply plugin: 'com.zwendo.restrikt'
Click to expand
First of all, you need to add the compiler plugin to the kotlin's maven plugin dependencies:
<dependency>
<groupId>com.zwendo</groupId>
<artifactId>restrikt-compiler-plugin</artifactId>
<version>[latest-version]</version>
</dependency>
Then, you need to add the annotations to your project's dependencies:
<dependency>
<groupId>com.zwendo</groupId>
<artifactId>restrikt-annotation</artifactId>
<version>[latest-version]</version>
</dependency>
Your pom.xml
should look like this:
<project>
<!-- ... -->
<build>
<!-- ... -->
<plugins>
<!-- ... -->
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>[kotlin-version]</version>
<!-- ... -->
<dependencies>
<dependency>
<groupId>com.zwendo</groupId>
<artifactId>restrikt-compiler-plugin</artifactId>
<version>[latest-version]</version>
</dependency>
<!-- ... -->
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.zwendo</groupId>
<artifactId>restrikt-annotation</artifactId>
<version>[latest-version]</version>
</dependency>
</dependencies>
</project>
Click to expand
Here are the currently supported default configuration options:
name | type | default | description |
---|---|---|---|
enabled |
boolean | true |
Whether the plugin is enabled |
automaticInternalHiding |
boolean | true |
Whether the internal symbols should be automatically hidden. |
annotationProcessing |
boolean | true |
Whether the plugin annotations should be parsed to manually hide symbols. |
toplevelPrivateConstructor |
boolean | true |
Whether to generate private constructor for top-level classes. |
defaultRetentionPolicy |
string | binary |
The default retention for the plugin's annotation |
Moreover, all annotations of the plugin can be individually configured using their own DSL (hideFromKotlin
,
hideFromJava
or packagePrivate
), with the following configuration options:
name | type | default | description |
---|---|---|---|
enabled |
boolean | true |
Whether the annotation should be processed to hide symbols. (works only if annotationProcessing is true ). |
retention |
boolean | binary |
The retention policy of the annotation. |
defaultReason |
string | none |
The default reason written on the annotation if no specific reason is provided. |
In addition to the options above, HideFromKotlin
annotation can be configured using the following options:
name | type | default | description |
---|---|---|---|
deprecatedMessage |
string | none |
The message written on the Deprecated annotation. |
Click to expand
You can configure the plugin using the configuration DSL.
restrikt {
option = value
// ...
}
To configure the annotations, a DSL function is available for each annotation:
restrikt {
hideFromKotlin {
option = value
// ...
}
}
Currently, the plugin is not configurable using Maven. The default configuration will be used.
Restrikt plugin features automatic hiding from internal symbols in Kotlin sources. At compile time, all symbols with the
internal
visibility automatically receives the JVM ACC_SYNTHETIC
flag, making them invisible to Java sources.
Restrikt plugin also features the generation of private constructors for top-level classes (classic top-level classes as well as facade classes generated by @JvmMultifileClass annotation). This is done to prevent instantiation of top-level classes from Java sources.
This plugin provides two annotations intended for symbol access restrictions. These two annotations, namely
HideFromJava
and HideFromKotlin
, are used to hide symbols from Java and Kotlin sources respectively. They can be
used on several targets such as classes, functions, properties, getters, setters, field etc. They are designed to be
used in the same way, just by placing the right annotation on the symbol to hide as follows:
@HideFromJava
fun someFunction() { // will be hidden from java sources
// ...
}
@HideFromKotlin
class SomeClass // will be hidden from kotlin sources
Both annotations also accepts a string parameter to indicate the reason of the restriction. If no message is provided, the default message defined in the plugin configuration will be used instead.
@HideFromKotlin(reason = "This class is designed for Java")
class Bar { // will be hidden from kotlin sources
// ...
}
Moreover, it is possible to configure the annotation retention directly on the annotation, using the retention
parameter. This parameter accepts the following enum values: source
, binary
, runtime
and default
. If no value is
provided, the default retention policy defined in the plugin configuration will be used instead.
@HideFromKotlin(retention = RestriktRetention.SOURCE) // will not be added to the class file
class Foo { // will be hidden from kotlin sources
// ...
}
Because sometimes you just want to hide code to the outside of your package, and because Kotlin doesn't provide a
package-private
visibility modifier, Restrikt plugin provides a PackagePrivate
annotation to hide symbols from
outside their package.
- All elements hidden by a 'Hide' annotation will still be accessible at runtime, meaning that already compiled code will still be able to access it ;
- Symbols hidden from Kotlin will still be accessible at compile-time from Kotlin sources in the same class (there is some very specific exceptions but the only access that always work is from the same class).
- Most IDEs won't warn you on the usage of a symbol made package-private by the
@PackagePrivate
annotation. However, at runtime, you will get anIllegalAccessError
if you try to access it from outside its package.
Problems listed below are in the process of being resolved. If you encounter an issue that doesn't seem to be in this list, feel free to open an issue for it.
All known issues have been resolved.
This section is intended for curious people and aims at describing the most specific parts of how this project works.
Like the Kotlin @JvmSynthetic, this
annotation induce the generation of the JVM ACC_SYNTHETIC
, hiding class members from Java sources. As for classes,
because the ACC_SYNTHETIC
doesn't work on them, the flag is applied to all the class members instead.
To effectively hide elements from Kotlin, the plugin generates on the marked elements the @Deprecated annotation. This annotation used with the DeprecationLevel.HIDDEN level, makes the element invisible to Kotlin sources, but still visible to Java sources.
// Foo.kt
@HideFromKotlin(reason = "java only")
class Foo {
// ...
}
// will be compiled to ...
// Foo.class
@HideFromKotlin(reason = "java only")
@Deprecated("java only", DeprecationLevel.HIDDEN)
class Foo {
// ...
}
Generating the Deprecated
annotation or simply using it directly have slightly different outcomes. Indeed, the
Deprecated
annotation (with HIDDEN
level) acts as a flag for the Kotlin compiler. The latter will add the JVM
ACC_SYNTHETIC
flag for the element in the produced classfile, making it also invisible for Java sources. The hack is
that the Kotlin compiler runs before calling the compiler plugin, so when it writes the classfile, the Deprecated
annotation is not present meaning that the ACC_SYNTHETIC
flag is not set.
- Add plugin support for maven projects ;
- Create a Restrikt IDEA plugin to prevent restricted symbols misuse ;
- Add support for generating annotations on all
public
(to be able to differentiateinternal
andpublic
) symbols of a project to simplify Kotlin project obfuscation with ProGuard.
Breaking Changes :
- Annotations now accepts a
retention
parameter to specify the annotation retention.
Features :
- Performance improvements by using a more efficient way to process symbols. Plugin is now lighter (from 900 to less than 300 lines for the plugin's backend).
Bugfixes :
- Plugin now properly works with inline functions.
Bugfixes :
- Fixed bug were Restrikt caused errors when compiling tests, solved by disabling the plugin for test sources.
Breaking Changes :
- Option
keepAnnotation
has been replaced by the newretention
option.
Features :
- Annotation retentions are now individually configurable
- Slightly improved performance by using a more efficient way to retrieve information from symbols.
- Plugin now works with maven projects.
Bugfix :
- Plugin now works with inline functions
- Plugin now correctly hides multi file classes functions
Features :
- Added the
PackagePrivate
annotation to force compiler to use thepackage-private
visibility ; - Plugin can now generate private constructors for top-level classes ;
HideFromJava
annotation now supports the File and Property targets ;HideFromKotlin
annotation now supports the Property target.
Bugfixes :
- 'Hide' annotations now works correctly on annotation classes declarations ;
- Automatic internal hiding now works properly on constructors.
Features :
- Automatic detection and hiding from internal symbols ;
- Added the
HideFromJava
annotation to hide symbols from Java sources ; - New gradle plugin configuration options for each annotation and internal hiding.