Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nicer way to optionally get a ContextPlugin extension #2102

Open
juggernaut0 opened this issue Feb 18, 2024 · 6 comments
Open

Nicer way to optionally get a ContextPlugin extension #2102

juggernaut0 opened this issue Feb 18, 2024 · 6 comments

Comments

@juggernaut0
Copy link

Describe the feature
A method on context similar to with(MyPlugin::class) but does not throw if the given plugin is not registered. It would simply return null instead.

Additional context
I am developing a utility library that can optionally be augmented by a plugin, and I couldn't find a way into the private pluginManager object, so right now I need to surround the ctx.with call with a try-catch to catch the PluginNotRegisteredException which is a little gross.

private fun <T> Context.maybeWith(clazz: KClass<out ContextPlugin<*, T>>): T? {
    return try {
        with(clazz)
    } catch (e: PluginNotRegisteredException) {
        null
    }
}

I haven't measured but I assume there is a performance overhead to throwing and catching an exception.

@tipsy
Copy link
Member

tipsy commented Feb 19, 2024

Hi @juggernaut0, could you tell us a bit more about your use case? How does the program recover if the plugin is not there?

@juggernaut0
Copy link
Author

I have some utility functions and plugins that are used across several projects, but not every project needs every plugin.

The code just assumes if the plugin is not there, it's not relevant to that app, so it skips a block and continues on.

There's plenty of workarounds like the try-catch, using nullable ctx.attribute to stash some state, (would prefer the more typesafe plugin api), always adding the plugin but configuring it do do nothing sometimes (feels like boilerplate), or making several versions of the functions.

Basically, the idea is augmenting behavior based on a plugin, but not requiring it to be installed.

FWIW I'm translating code from Ktor, which has a pluginOrNull function.

@tipsy
Copy link
Member

tipsy commented Feb 19, 2024

The code just assumes if the plugin is not there, it's not relevant to that app, so it skips a block and continues on.

So something like logging, tracing, analytics?

FWIW I'm translating code from Ktor, which has a pluginOrNull function.

I supposed we could have withOrWithout(MyPlugin) (only half-joking 😄)

I'm not a fan of how withOrNull sounds, so maybe your maybeWith or tryWith. Feel free to submit a PR, and we can discuss the naming there.

@dzikoysk
Copy link
Member

Wouldn't it be easier to just cover this with app data?

 // Javalin's key
data class Key<T>(val id: String)

// Define a key
val OptionalMetrics = Key<Metrics?>("optional-metrics")

// Register data
cfg.pvt.appAttributes[OptionalMetrics] // null or not

// Handler
ctx.appData(OptionalMetrics)?.example("abc")

I'm not sure why there's no public register function for app data, so @tipsy may need to clarify this area.

@tipsy
Copy link
Member

tipsy commented Feb 19, 2024

I'm not sure why there's no public register function for app data, so @tipsy may need to clarify this area.

From https://javalin.io/documentation#app-data:

val app = Javalin.create { config ->
    config.appData(myKey, myValue)
}

@dzikoysk
Copy link
Member

Okay, my bad, I was looking at 5.4.3-SNAPSHOT 🤦‍♀️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants