Eager singleton

I want to run init method in singleton object while application started (before first access to object). Is there any way to do this?

More details, I would like to solve next problem: I have a class (singleton), it contains list and method:

object FileValidatorManager {

    private val validators: MutableList<FileValidator> = mutableListOf()

    fun register(validator: FileValidator) {
        validators.add(validator)
    }

    fun validateFile(file: File): Boolean = validators.stream().allMatch { it.validate(file) }

    interface FileValidator {
        fun validate(file: File): Boolean
    }

}

Now I want to call method FileValidatorManager#register in every implementation of FileValidator in init method, but init method will work only after first access to implementation. Can I run init method without access?

Tthe init block is called when the class is first loaded. The same applies to other global values (top level properties).
You can load the class several ways but another alternative is to force users of your code to call an explicit initialize function on your object to control this functionality. Still, this is probably not the best design (all say why I think so lower in the reply).

I’m not sure I understand what you’re wanting to do here. The phrasing of it makes me suspect you want every newly constructed FileValidator to automatically register itself with the FileValidatorManager. This kind of automatic registration could be replaced by requiring the users to register the file validators themselves.

Still if you want all types of FileValidators to be registered automatically without control, you could use an abstract class instead of an interface. Your FileValidator class can do all of it’s initialization in it’s init block as it sees fit. Every subclass receives the guarantee (like all subclasses) that the parent is properly initialized before the subclass does it’s own specialized initialization.

This kind of initialization of state and ordering of initialization is a primary purpose behind classes. If you still want an interface that’s okay but in order to keep the behavior of registering all implementations, you’ll still need a general use class combined with some creational design pattern. (For example keep the FileValidator but have all implementations extend AbstractFileValidator)

Since you’re using a global singleton for the manager that you want to use in all FileValidators, your manager looks more like a companion object. After all, a companion object is defined as a member of every instance of a type. You might consider moving FileValidatorManager into a companion object since that’s how you’re already using it.

Lastly, why are you using a singleton? A singleton is rarely the answer as it’s just another global. In some circles, saying the word singleton is enough to trigger some people’s code-smell reflex :wink:
Your singleton for here means you give up a lot of control. You give up multi-tenency (e.i. Only one FileValidatorManager group at time!). You also give up raw testing and mocking.

You could make FileValidatorManager into a class and create a global val that holds a default group. Even then I would avoid that and just initialize it for each application (or test suite, etc).

You’ll find that your entry points should be small and do all of this kind of initialization for your program. Having globals force unchangeable defaults causes a lot of pain. There’s always the exception for short throw-away scripts though.
Most of my main methods end up looking like 5-10 lines of creating all of my “singleton” objects and configuring them–same as you’d do for dependency injection or service registration.

Thank you for detailer and quick answer. I liked idea with abstract class and registration in init block of this class. But it is still does not working (or I do it wrong) :

abstract class AbstractFileValidator : FileValidatorManager.FileValidator {
    init {
        FileValidatorManager.register(this)
    }
}

class PdfExtensionValidator : AbstractFileValidator() {

    override fun validate(file: File): Boolean = file.extension == "pdf"

}

My singleton class is not changed. Init method not run. What I do wrong?

PS
I read your recommendations for architecture of my code. I learn kotlin recently and still not know about features of the language. Thank you for help!

Here’s a runnable example of your code with the abstract class. When you run it you will see that the println does get called when constructing an instance of pdfValidator:

abstract class AbstractFileValidator {
    init {
        println("registering now")
    }
}

class PdfExtensionValidator : AbstractFileValidator()

fun main() {
    val pdfValidator = PdfExtensionValidator()
}

Maybe the issue is somewhere else in your code?

1 Like

You called PdfExtensionValidator in #main function, I did not call.

I just use FileValidatorManager.validate(file) and I want to have all validators register in manager.

1 Like

Ah, maybe I misunderstood.
I thought you wanted every instance of your validators to be registered when they are created.

Or do you want the validator types to be detected as an available type and your manager to then create and register them?

Maybe a better way of asking it: Who is responsible for instantiating the validators?
If I’m adding my own FileExtensionValidator that takes as a constructor argument a string to check, who passes in that string? Could I do val pdfValidator = FileExtensionValidator("pdf") or would I need to give the configuration through some other means?

If your manager is the one instantiating and configuring the validators, you’ll have to do something like the following: use reflection and require all subclasses have a specific constructor, or use an abstract factory or other pattern, or use a library that provides dependency injection, or make all validators top level properties or objects and require the class is loaded.

Another thing to consider is what happens when you have more than one of the same type of validator?
So what if I have this:

val pdfValidator = FileExtensionValidator("pdf")
val xmlValidator = FileExtensionValidator("xml")

This works because I’m assuming , as the user, can create multiple instances of the same validator type with different configurations. If the manager has that responsibility and only creates a single validator per type then I’ll be forced to create two classes that do the same thing.

1 Like

You misunderstood or I didn’t explain it well. Once again.

No, one implementation - one validator.

For example, let I have a problem: check files on three conditions: extension - pdf, size - not greater than 200mb, name - contains only latin characters and does not contains whitespaces. To solve this, I creating three implementation of FileValidator (which extends AbstractFileValidator), every implementation register in FileValidatorManager, and when I run FileValidatorManager#validate(file) - result is validating file by every validator.

A week later I get new requirement: check file created date. To solve this, I just should create one new implementation and register it in manager.

Maybe my problem is very strange, but it just example. I really need to know is it possible in kotlin or not. :upside_down_face:

Ah okay I see. So you want every validator to be, functionally, a singleton. Meaning for every implemention, you want a single instance of that validator type to be created and handled by the manager.

You could do that by making all validators top level objects (the quickest way of making a singleton in Kotlin). The constructor will be called when the class is loaded and immediately register as per the AbstractValidator constructor.

Overall I still think singletons will be tough. Not only are you giving up multi-tenency of your Validators manager but you’re also giving up multi-tenency of all validators.
Every small change in a validator would require a new type. So instead of reusing one FileSizeLimit to restrict PDFs (FileSizeLimit("pdf", 200.mb) and XML files (FileSizeLimit("pdf", 10.kb)), I would have to make two classes.

If that is your goal, another option is to avoid classes all together. Instead of having classes you could directly register lambdas like this:

FileValidatorManager.register { /* ... */ }

This solved the problem of having to force the class is loaded to trigger static code (which is kinda a hacky solution anyways) or forcing you to scan through all classes to look for implementions (which has it’s own problems).

1 Like

If you don’t mind using external libraries, Reflections (org.reflections:reflections:reflections or net.oneandone.reflections8:reflections8 for Java8+ support) may help.

What I usually do is something like this:

 Reflections(Frequency::class.java.packageName)
                    .getSubTypesOf(Frequency::class.java)
                    .forEach {
                        // Do whatever you want to do maybe by reflection API
                    }

The above example assumes all the classes are in the same package, but that’s only for performance. It is easy to widen the search.
If the instances are objects (singletons), you may access them like this:

        Reflections(RoutedHandler::class.java.packageName)
                .getSubTypesOf(RoutedHandler::class.java)
                .forEach {
                    logger.info("Adding routes for ${it.simpleName}")
                    val i = it.kotlin.objectInstance!!
                    i.addRoutes(server)
                }

(The above example registers all route handler implementations for Javalin server.)

My option is good, when all the instances are available at the time of call.

1 Like

I was thinking about reflections, but I would like to use language tools.

Can you please write part of code where you declare abstract class and one of its implementation? I really not understand how do it correctly. My program still doesn’t work (validators not registered in manager).

1 Like

I think what @arocnies means is something like this

abstract class Foo 
object Bar : Foo() {
    init {
        println("this is called when Bar is created as a singleton object")
    }
}

The problem with this is that it’s impossible to fully control when a singleton object is loaded. Objects in kotlin are created when the jvm classloader loads the .class file the compiled code for that class is stored in. When this happens depends on the JVM implementation you use. You can force a class to be loaded by calling the right functions on the classloader or just using the class but that is pretty much the same as initializing your validators by hand.
All this assumes that you are using KotlinJVM and not native or JS. I’m not sure how exactly object initialization works on those target platform. AFAIK this is not documented anywhere and my knowledge on the JVM comes from me figuring out the same problem you seem to have.

Kotlin doesn’t have a language tool that lets you run code at startup (independent from the main function).
The best I could come up with is using some sort of custom annotation processor. Sadly my solution is not open source and I can’t easily extract it from my project since it is just a small feature in a larger project. If there is enough interest I might take the work to do so though.
In any case what I do is that I mark the functions that I want to call at startup with a simple annotation.

@MyCustomStartup
fun foo() {
    // do some init here
}

I then have a custom annotation processor that finds all functions with that annotation and combines them into on function calling all of them

// generated
fun myBigStartupFunction() {
   foo()
   // etc
}

That way I only have to call myBigStartupFunction at the start of the main function and all initialization is done automatically. The only issue with my current setup is that you have to call myBigStartupFunction for all libraries that use that system so my main function looks something like

fun main() {
    startupLibrary1()
    startupLibrary2()
    startupMainProgram()
   
    actualMain()
}

The other way to solve this is to use reflection. That should work fine as well but it might lead to issues if your annotated functions are in different packages of even compiled into multiple .jar-files. I remember having some issues with the classloader not finding some annotated stuff because it hadn’t been loaded at that point. It’s probably not something to worry about unless you have a really complicated startup but that’s why I chose to use code generation this time.

1 Like

In short: you can’t do it purely by language tools without an init call contract. You can’t do it for two reasons: there are no tool (not even in kotlin-reflect) to scan all subtypes of a class/interface and for lazy class loader. (Ok, you can make your own ClassLoader, but I think that is too much work for achieving your goal.)

You can’t do it by making top level objects directly, because they are instantiated and initialized only when the file first accessed.

Before I decided to use the Reflections lib, I did the following: made the objects on top level and put them in an array:

interface Filter { ... }

object RarityFilter : Filter { ... }

object RaceFilter : Filter { ... }

[...]

val TheFilters = listOf(
        NameFilter,
        RarityFilter,
        RaceFilter,
        AttackTypeFilter,
        StrategyTypeFilter,
        HasLevelUpFilter,
        HasRebornFilter,
        HasEvolveFilter,
        RebornCountFilter
)

Then, in my main I did some useless and harmless access to the array:

logger.debug("Number of filters: ${TheFilters.size}")

But this is a hack and a lot of boiler code. Also you can’t avoid a call in your main so this is literally the same as creating a register function and forcing to call that by the user. So some kind of init call can’t be avoided due to the lazy class loading.
To do this you can either make an initializer in your lib and make a contract for your library to be called this init, as mentioned before.

Using Reflections still avoid the need to add all your implementations manually. If your lib has a single or just a few entry points, you can make the init lazy by making the list lazy (by lazy {}) and using the Reflections scan there. In these cases you can hide your Reflections usage implementation level.

3 Likes