Value from x-jvm-package included in Handler and Resource name
x-jvm-package is a very useful feature for splitting up routes and handlers, but the generated names of the Handler trait and Resource object seem redundant.
Assuming package foo is specified at the build tool level, without x-jvm-package specified, foo.Handler and foo.Resource are generated. This is good. But when x-jvm-package: bar is added, foo.bar.BarHandler and foo.bar.BarResource are generated. Since the option is for package naming, seems like it should be foo.bar.Handler and foo.bar.Resource. The latter would also make for more consistent code that's easier to change when x-jvm-package is changed.
Things get even worse if you specify x-jvm-package: bar.baz: foo.bar.baz.BarbazHandler and foo.bar.baz.BarbazResource are pretty ugly names.
I could take a crack at fixing this if the change sounds good?
Sorry for the late reply here -- The intent behind the duplication is to avoid conflicts when importing multiple clients at the same time, the naming pattern just naturally carried over to servers as well (much for the same reason).
I've seen multiple server implementations in the same file, if they are contextually linked and very small, so I'm hesitant to make this change.
Additionally, x-jvm-package: bar.baz: foo.bar.baz.BarbazHandler isn't actually how it would work, as it just takes the last segment. You'd end up with foo.bar.baz.BazHandler.
No worries, thanks for the reply.
I understand the need to disambiguate between multiple clients or handlers imported into the same file - we have this situation ourselves. In our case, however, we need to use the package naming for disambiguation anyway. We might have a FlightResource from both an api.v1.flight package and an api.v2.flight package. These are sourced from different OpenAPI files with different ScalaServer entries in build.sbt. So it ends up looking like this:
import com.example.api.v1
import com.example.api.v2
// from x-jvm-package: flight, used in both versions
v1.flight.FlightResource
v2.flight.FlightResource
// from x-jvm-package: payment, used in both versions
v1.payment.PaymentResource
v2.payment.PaymentResource
It would be nice if we could just say v1.flight.Resourceetc.
You're right about the bar.baz situation.... what I was thinking of was that x-jvm-package: manywords gives you ManywordsHandler which looks kind of funny. You would want ManyWordsHandler, but there's no way to take that from the package name which loses word separations by convention. This part isn't a huge deal, but it sort of underscores that we're taking a package name component and putting it into something that isn't a package name.
Maybe a compromise would be to drop x-jvm-package from the handler/resource name, but add an additional x-jvm-object-prefix option for those who really want to put something in front of Handler and Resource? Prefixing these terms is already an opt-in feature requiring an OpenAPI extension.
Ah, I see where you're coming from now.
The state of the world currently is as follows, given the following identifiers:
-
{a}.{b}.{c}Handler -
{a}.definitions.{d}.Foo
| Label | What | Does |
|---|---|---|
a |
ScalaClient(...,pkg=???) in build configuration |
Ultimate prefix for whatever prefixes are defined in the spec |
b |
x-(jvm|scala|java)-package |
Defines individual component layout for clients and servers |
b |
tags |
Fallback for if x-(jvml|scala|java)-package is not present |
c |
tags: [foo, bar, baz] x-jvm-package: foo.bar.baz |
the last value, capitalized, is prefixed to generated classes for disambiguation |
d |
ScalaClient(...,dtoPkg=???) in build configuration |
work around possible package conflicts for generated models |
I think having an x-jvm-object-prefix would make sense if the semantics of c were not already established. To maintain backwards compatibility, we'd need to have this work like x-jvm-object-prefix: '' which would really be unfortunate to use.
I hesitate to say, but if you were to flip your package structure to be flight.v1.V1Resource with flight.definitions.v1.Foo, it might be less onerous, as the disambiguation would make sense.
I'm curious about your thoughts on avoiding x-jvm-object-prefix: ''
One note, as for manywords, if you called it manyWords you would actually end up with ManyWordsHandler, fwiw, thanks to the work from @kelnos.
Understood, thanks for those details.
I hesitate to say, but if you were to flip your package structure to be
flight.v1.V1Resourcewithflight.definitions.v1.Foo, it might be less onerous, as the disambiguation would make sense.
The trouble with this is that it implies that there can be different versions for flight than there are for payment. Ultimately it's the entire API that's versioned, not individual sections, and the package structure should reflect that.
One note, as for
manywords, if you called itmanyWordsyou would actually end up withManyWordsHandler, fwiw, thanks to the work from @kelnos.
This is handy, and I'll keep it in my back pocket!
I think having an
x-jvm-object-prefixwould make sense if the semantics ofcwere not already established.
Yeah that's the problem, I suppose. I know you're trying to maintain compatibility in the generated source. As a user it wouldn't bother me too much if the compatibility was broken here, especially since the lib is pre-1.0.0. But I realize this is a tough line to walk.
I'm curious about your thoughts on avoiding
x-jvm-object-prefix: ''
Yeah not sure it's avoidable without breaking compatibility. I could live with it if it were a transitional measure though, with it eventually being unnecessary.
I was going to say that prefixing the Handler/Resource names is not really necessary to disambiguate anyway, since you can do things like import renaming or importing a package that can be used to prefix the name and thus disambiguate it. But, I suppose that's only a Scala feature and supporting Java is also a goal of this lib. Probably forcing Java users to use fully qualified names is not great.
This, combined with making the semantics around tags opt-in instead of opt-out, make sense to consider as we move towards a 1.0 release.
I'd like one non-JVM language (currently looking at Python) to ensure we don't accidentally bake JVM-isms into the codegen.
To that point, as much as it would be easy to just say that Scala and Java Handler/Resource should be named the same, the semantics there actually don't need to match at all, if we had something like x-(jvm|scala|java)-object-prefix.
The intent is to keep frameworks within a language as close as we can reasonably get, to make akka-http -> http4s -> ??? easier, but trying to maintain that across language semantics is definitely not a goal (builders in Java, for instance, vs sensibly named parameters in Scala).