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

Is it possible to allow functions *outside* of a class definition to be used as a JsonCreator or similar? #435

Open
ragnese opened this issue Apr 8, 2021 · 5 comments

Comments

@ragnese
Copy link

ragnese commented Apr 8, 2021

Use case
Basically, the idea is that I might design a class where I want to use a factory function without needing to write:

companion object {
    @JvmStatic
    @JsonCreator
    private fun creator(arg1: Arg1, arg2: Arg2) = myFactoryFunction(arg1, arg2)
}

Describe the solution you'd like

I rather just be able to say:

@JsonDeserialize(with = ::myFactoryFunction)
class MyClass () {}

or maybe:

@JsonCreator(for = MyClass::class)
fun myFactoryFunction(arg1: Arg1, arg2: Arg2): MyClass = TODO()

Describe alternatives you've considered
My first option was to do:

companion object {
    @JvmStatic
    @JsonCreator
    operator fun invoke(arg1: Arg1, arg2: Arg2) = TODO()
}

Which is almost perfectly fine. Now I can just call MyClass(arg1, arg2) in my regular code because of the operator invoke and it works as a JsonCreator just fine. However, if I have to reference the invoke function in other code, I have to write MyClass.Companion::invoke instead of ::MyClass like you would for a true constructor or a top-level factory function. So, since I hate the ugly invoke reference, I've taken to writing the top-level factory function and then writing a private companion function as the JsonCreator that does nothing but call the true factory function. I'd like to eliminate this "boilerplate".

@dinomite
Copy link
Member

dinomite commented Apr 9, 2021

Interesting—this might be something best done in Databind where support for your proposed with or for arguments to @JsonCreator could be added, then it would Just Work™ anywhere Jackson is used.

@ragnese
Copy link
Author

ragnese commented Apr 10, 2021

That could be, but I have a feeling it would be a weird ask for the Java-side of things. There are no free functions in Java, so the idea of a class having a creator method for a different (non-inheritance-related) class would be pretty weird.

@cowtowncoder
Copy link
Member

@ragnese the usual split would be that jackson-databind had an extension point that allows certain kinds of configurability -- such as "external" creators -- and then modules (like Kotlin or Scala module) could implement something using them.

Mechanism that exists (at very general level) is ValueInstantiator, and I think Kotlin module already adds a few things.
There is nothing preventing adding more functionality, although there isn't necessarily much support either.

One possibly related feature that has been requested before, fwtw, is the ability to use actual static factory method defined in a mix-in class, instead of only using annotations from mix-in class.
Allowing this would be relatively easy but I have been hesitant since it is conceptually diverging from the original idea of mix-ins.
I don't know if that helps here at all but thought I'll mention just in case.

@ragnese
Copy link
Author

ragnese commented Apr 10, 2021

@cowtowncoder

Interesting. I'm not familiar with what you're describing about using annotations from mix-in classes (and therefore I also don't understand the request feature you're describing). Could you elaborate? I'm not even sure what "mix-in" means in this specific context.

@cowtowncoder
Copy link
Member

@ragnese Jackson allows addition of "mix-in annotations", explained f.ex here:

https://medium.com/@shankar.ganesh.1234/jackson-mixin-a-simple-guide-to-a-powerful-feature-d984341dc9e2

so you can basically say "use annotations this class/interface has same as if they were part of class [target class]".
That is useful with classes you cannot (or don't want to) modify.
Nothing else is used of such classes; no bytecode manipulation is used etc, just annotation values via reflection.
But in theory it wouldn't too difficult to use one specific kind of other thing: static factory methods: so some users have assumed that factory methods of such mix-in classes could be used.

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

No branches or pull requests

3 participants