How to find all classes in a package using reflection in kotlin - kotlin

Is it possible to find all kotlin classes in a given package?
I also need only annotated classes but it's not a big deal. Any suggestions ?

Kotlin on the JVM suffers the same issue as Java in this regard due to the implementation of class loaders.
Class loaders are not required to tell the VM which classes it can provide, instead they are just handed requests for classes, and have to return a class or throw an exception.
Source and more information: Can you find all classes in a package using reflection?
To summarize the linked thread, there are a number of solutions that allow you to inspect your current class path.
The Reflections library is pretty straight forward and has a lot of additional functionality like getting all subtypes of a class, get all types/members annotated with some annotation, optionally with annotation parameters matching, etc.
Guava has ClassPath, which returns ClassInfo POJO's - not enough for your use case, but useful to know as Guava is available almost everywhere.
Write your own by querying classloader resources and code sources. Would not suggest this route unless you absolutely cannot add library dependencies.

Here's an example of querying classloader resources, adapted from https://www.javaworld.com/article/2077477/java-tip-113--identify-subclasses-at-runtime.html
Requires Java 8 or higher.
// Call this function using something like:
// findClasses("com.mypackage.mysubpackage")
// Modified from https://www.javaworld.com/article/2077477/java-tip-113--identify-subclasses-at-runtime.html
fun findClasses(pckgname: String) {
// Translate the package name into an absolute path
var name = pckgname
if (!name.startsWith("/")) {
name = "/$name"
}
name = name.replace('.', '/')
// Get a File object for the package
val url: URL = Launcher::class.java.getResource(name)
val directory = File(url.getFile())
println("Finding classes:")
if (directory.exists()) {
// Get the list of the files contained in the package
directory.walk()
.filter { f -> f.isFile() && f.name.contains('$') == false && f.name.endsWith(".class") }
.forEach {
val fullyQualifiedClassName = pckgname +
it.canonicalPath.removePrefix(directory.canonicalPath)
.dropLast(6) // remove .class
.replace('/', '.')
try {
// Try to create an instance of the object
val o = Class.forName(fullyQualifiedClassName).getDeclaredConstructor().newInstance()
if (o is MyInterfaceOrClass) {
println(fullyQualifiedClassName)
// Optionally, make a function call here: o.myFunction()
}
} catch (cnfex: ClassNotFoundException) {
System.err.println(cnfex)
} catch (iex: InstantiationException) {
// We try to instantiate an interface
// or an object that does not have a
// default constructor
} catch (iaex: IllegalAccessException) {
// The class is not public
}
}
}
}

Related

How do you set up a property in a custom gradle task?

I want to write a task that takes a directory from , does something with the files in it and writes the result into some other directory to.
I've been led to believe this was the way to define such a task (kotlin dsl):
package my.app
abstract class FooBarTask : DefaultTask() {
#get:InputDirectory
abstract val from: Property<Directory>
#get:OutputDirectory
abstract val to: Property<Directory>
#TaskAction
fun doSomething() {
println("Hakuna Matata")
}
}
now how do I set the from and to value in a groovy-based build.gradle?
def myTask = tasks.register('myTask', FooBarTask) {
from = layout.projectDirectory.dir("foo")
to = layout.buildDirectory.dir("bar")
}
this results in
Could not create task ':my-subproject:myTask'.
> Please use the ObjectFactory.directoryProperty() method to create a property of type Directory.
and it shouldn't.
How do you correctly define a directory property in a custom task?
Gradle has the specialized DirectoryProperty, that offers some additional functionality, compared to the plain Property<Directory> which is one of the implemented interfaces. So this specialized type should be used when declaring directory inputs/outputs.
I'm actually not a 100% sure what caused the error you saw.

Null property provided by Gradle when using custom plugin

I'm trying to follow the Gradle custom plugin documentation to create a plugin that can be configured.
My plugin code:
interface MyExtension {
var myValue: Property<String>
}
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
val extension = project.extensions.create<MyExtension>("myExt")
}
}
in build.gradle.kts:
plugins {
`java-library`
}
apply<MyPlugin>()
the<MyExtension>().myValue.set("some-value")
Running this will give
Build file '<snip>/build.gradle.kts' line: 6
java.lang.NullPointerException (no error message)
Turns out the the<MyExtension>().myValue is null, so the set call fails. How do I do this correctly? Did I miss something in the documentation, or is it just wrong?
The documentation is not wrong. Properties can be managed by either you or by Gradle. For the latter, certain conditions have to be met.
Without managed properties
If you want to be completely in charge, you can instantiate any variables you declare yourself. For example, to declare a property on an extension that is an interface, it could look like this:
override fun apply(project: Project) {
val extension = project.extensions.create("myExt", MyExtension::class.java)
extension.myValue = project.objects.property(String::class.java)
}
Or you could instantiate it directly in the extension by making it a class instead:
open class MessageExtension(objects: ObjectFactory) {
val myValue: Property<String> = objects.property(String::class.java)
}
However, a property field is not really supposed to have a setter as the property itself has both a setter and a getter. So you should generally avoid the first approach and remove the setter on the second.
See here for more examples on managing the properties yourself.
With managed properties
To help you reduce boilerplate code, Gradle can instantiate the properties for you with what is called managed properties. To do use these, the property must not have a setter, and the getter should be abstract (which it implicitly is on an interface). So you could go back to your first example and fix it by changing var to val:
interface MyExtension {
val myValue: Property<String> // val (getter only)
}
Now Gradle will instantiate the field for you. The same thing works for abstract classes.
Read more about managed properties in the documentation here.

How to access `JavaToolchainSpec` from within custom Gradle task

According to "Toolchains for plugin authors" it should be possible to access the configured JavaToolchainSpec from within a custom task. I try to use this approach within a custom plugin which creates a task based on the presence of the JavaPlugin and queries the configured languageVersion property. Here is a minimal example.
build.gradle
plugins {
id 'application'
id 'com.example.myplugin'
}
...
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
MyPlugin.kt
class MyPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.plugins.withType<JavaPlugin> {
target.tasks.create<MyTask>("mytask")
}
}
}
MyTask.kt
abstract class MyTask : DefaultTask() {
init {
val extension = project.extensions.getByType<JavaPluginExtension>();
val languageVersion = extension.toolchain.languageVersion.get();
...
}
}
Once Gradle creates MyTask and the languageVersion property is queried, the build fails with the following error.
Cannot query the value of property 'languageVersion' because it has no value available.
My guess is that I am accessing the extension too early and it has not set its values at this time. My question now is if there is a way to wire up the configured properties (ideally with lazy mechanisms) with the task.
apparently you have to configure the toolchain object in the java plugin extension to be able to use JavaToolchainService, using something like:
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
if you don't do that Gradle will defaults to the current JVM and the whole toolchain API will be unavailable (leaving you with the error you reported)

Using Generic swift enum in a protocol

I have case where I often scratch my head around, let's say I have a generic Manager class in a pod that can handle permission, and within the app, I want to be able to extend it to create more meaningful method name, aka to use with enum as parameter, to make its use more clear and less prone to mistake.
But it seems that you can't call private method when you create the extension elsewhere.
I'm sure there would be a more clean way with Generic/AssociatedValue or maybe my pattern is just wrong...
Here's the simplified version of it:
Class in the external pod:
public class FeatureDataManager {
public static let shared = FeatureDataManager()
private var permissionManager: PermissionManager!
private init() {
self.permissionManager = PermissionManager()
}
private getPermission(forFeature feature: String) -> Bool {
return self.permissionManager.isEnable(feature)
}
}
and the extension in the app:
extension FeatureDataManager {
enum FeatureType: String {
case ads = "ads"
case showBanner = "banner"
case showFullScreenPub = "showFullScreenPub"
}
public func isPermissionEnable(forFeature feature: FeatureType) {
// Does not compile, visibility issue
self.getPermission(forFeature: feature.rawValue)
}
}
Clarification:
FeatureDataManager is a class in the Pod that is solely used to check for permissions in the form of String value across many app that are using importing it.
I wanted each single app using it, to define an extension that would have their own finite enum of their supported permissions. Let's say App A support Ads, but not App B. So I wanted to have a universal method that when you call featureManager.isPermissionEnable(.Ads), whenever app that is, the auto-complete would just offer the list of the supported permission for that app. Also, the goal of wrapping my string permission value into an enum is to be more bulletproof to mistake and easier refactoring if a name change, just have to change it in a single place.
What you're looking for would be a "protected" level, and that doesn't exist in Swift, and can't exist without creating a new protection level, since it would break compiler optimizations. In your example, since getPermission(forFeature:) is promised never to be called outside this scope, the compiler is free to inline it. So this function may not even exist at the point that your extension wants to call it.
It would be possible for Swift to add a "protected" level that is "semi-public," but Swift does not have any such feature. You will need to redesign FeatureDataManager to make this possible. From your example, it's not obvious how to do that, because you provide no public interface for permissions at all, so it's not clear what you mean by "I want to be able to extend it to create more meaningful method name." Currently there is no public method name. If there were one, then making a more convenient syntax like you describe would be easy.
Can you give an example of the calling code that you want this extension to improve?
For more on why the language is this way, see Access Control and protected. It's not an accident.
You note that you can do this in the same file, and that's true. Swift allows this for stylistic reasons (many people use extensions inside a single file for code organization reasons). Swift treats all extensions in the same file as being in the main definition. But that does not extend to other files, and certainly not to other modules.
The generic solution to this looks like:
public class FeatureDataManager<Feature>
where Feature: RawRepresentable, Feature.RawValue == String {
private func getPermission(forFeature feature: String) -> Bool { ... }
public func isPermissionEnable(forFeature feature: Feature) {
self.getPermission(forFeature: feature.rawValue)
}
}
An App would then create a feature set and create a manager for that feature set:
enum AppFeature: String {
case ads = "ads"
case showBanner = "banner"
case showFullScreenPub = "showFullScreenPub"
}
let featureDataManager = FeatureDataManager<AppFeature>()
featureDataManager.isPermissionEnable(forFeature: .ads)
That does prevent the easy creation of a .shared instance. It's arguable whether that's good or bad, but on the assumption that you want it, you would need to wrap it up:
class AppFeatureDataManager {
enum Feature: String {
case ads = "ads"
case showBanner = "banner"
case showFullScreenPub = "showFullScreenPub"
}
static var shared = AppFeatureDataManager()
let manager = FeatureDataManager<Feature>()
public func isPermissionEnable(forFeature feature: Feature) {
manager.isPermissionEnable(forFeature: feature)
}
}
Now that's a bit too much boiler-plate for the app side (especially if there are more methods than isPermissionEnable), so you can remove the boilerplate this way (full code):
public class FeatureDataManager<Feature>
where Feature: RawRepresentable, Feature.RawValue == String {
private var permissionManager: PermissionManager
init() {
self.permissionManager = PermissionManager()
}
private func getPermission(forFeature feature: String) -> Bool {
self.permissionManager.isEnable(feature)
}
public func isPermissionEnable(forFeature feature: Feature) {
self.getPermission(forFeature: feature.rawValue)
}
}
protocol AppFeatureDataManager {
associatedtype Feature: RawRepresentable where Feature.RawValue == String
var manager: FeatureDataManager<Feature> { get }
}
// Here you can write any necessary pass-through functions so the app doesn't have to
extension AppFeatureDataManager {
public func isPermissionEnable(forFeature feature: Feature) {
manager.isPermissionEnable(forFeature: feature)
}
}
//
// Application Developer writes this:
//
class MyGreatAppFeatureDataManager {
enum Feature: String {
case ads = "ads"
case showBanner = "banner"
case showFullScreenPub = "showFullScreenPub"
}
// This is the only thing that's really required
let manager = FeatureDataManager<Feature>()
// They're free make this a shared instance or not as they like.
// That's not something the framework cares about.
static var shared = MyGreatAppFeatureDataManager()
private init() {}
}
All that said, I think this is getting too many layers if FeatureDataManager is really just a front-end for PermissionManager like you've described here. (Maybe your example is highly simplified, so the below doesn't apply.)
If PermissionManager is public, and the real goal is just to have a nicer front-end to it, I would write it this way:
protocol FeatureDataManager {
associatedtype Feature: RawRepresentable where Feature.RawValue == String
var permissionManager: PermissionManager { get }
}
extension FeatureDataManager {
func isPermissionEnable(forFeature feature: Feature) {
permissionManager.isEnable(feature.rawValue)
}
}
//
// App developer writes this
//
class MyGreatAppFeatureDataManager: FeatureDataManager {
enum Feature: String {
case ads = "ads"
case showBanner = "banner"
case showFullScreenPub = "showFullScreenPub"
}
// This is the only required boilerplate; the protocol can't do this for you.
let permissionManager = PermissionManager()
// And the developer can decide to make it a shared instance if they like,
// but it's not the business of the framework
static let shared = MyGreatAppFeatureDataManager()
private init() {}
}
The private access control restricts the use of an entity :
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file.
Access Control - The Swift Programming Language
If you want an entity accessible through class extension (in another file and in the same module/package) : use internal access control.
If you want an entity accessible through class extension (in another file and in another module/package) : use public access control.
You have to declare fileprivate access level to access it in an extension defined in same file. You cannot access private entities out of its defined scope, even if extension relies on same file!

Koin - How to generify Singleton creation?

I have a class InteractorCache<T> that I would like to inject in different places using Koin.
I would like to create a singleton instance of that class based on the type T. So if I have 10 types T, I would like 10 different singletons.
So far I managed to do the above with the following code (this is an example with only 2 types, A and B):
val interactorAModule = module {
factory {
InteractorA(get())
}
}
val aCache = module {
single(named("A")){
InteractorCache<List<A>>()
}
}
val interactorBModule = module {
factory {
InteractorB(get())
}
}
val bCache = module {
single(named("B")){
InteractorCache<List<B>>()
}
}
This works but there is a lot of repetition as I have to create a new cache module (aCache, bCache) every time I create a new type. I would like to be able to do something like this instead:
val cacheModule = module{
single<T>{
InteractorCache<T>()
}
}
so there is only 1 declaration that works for any type T.
Is there a way to do this in Koin?
Although this is late but the idea of making generic or T a singleton is bad idea, when you declare a class singleton it will run a single instance, so runtime error would be InteractorCache() is incompatible or mismatched to InteractorCache() as the first class you would assign the T for example the class A InteractorCache() it would be fixed instance of A and cannot anymore assign to class B.