jackson-module-kotlin icon indicating copy to clipboard operation
jackson-module-kotlin copied to clipboard

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

Open ragnese opened this issue 4 years ago • 5 comments

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".

ragnese avatar Apr 08 '21 13:04 ragnese

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.

dinomite avatar Apr 09 '21 13:04 dinomite

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.

ragnese avatar Apr 10 '21 00:04 ragnese

@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.

cowtowncoder avatar Apr 10 '21 00:04 cowtowncoder

@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.

ragnese avatar Apr 10 '21 01:04 ragnese

@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.

cowtowncoder avatar Apr 10 '21 01:04 cowtowncoder