hilla
hilla copied to clipboard
Support @JsonCreator and @JsonValue when generating TypeScript from Java
Describe your motivation
In Java, it is a good practice to use domain primitives rather than ordinary primitives in certain situations. For instance, instead of using a String
or long
as the customer ID, you should create a CustomerId
type that wraps a String
or long
. It should be possible to use domain primitives like this in @BrowserCallable
services.
Describe the solution you'd like
Although having domain primitives in TypeScript would be nice, it isn't as important as having them in Java. I would be fine with a solution where I can use domain primitives in Java and basic types in TypeScript. The easiest way to do this would be to support @JsonValue
and @JsonCreator
on the Java side.
My CustomerId
class would have a method (maybe toString()
) annotated with @JsonValue
. An outgoing CustomerId
object would then be serialized to a string
in TypeScript.
I would also have a corresponding constructor that accepts a single String
parameters and is annotated with @JsonCreator
. An incoming TypeScript string
would then be deserialized to a CustomerId
object.
Describe alternatives you've considered
I could make separate @BrowserCallable
services and DTOs that use ordinary primitives and do the conversion manually on the Java side before delegating to the "real" services and DTOs that use domain primitives. However, this feels like unnecessary complexity if the only difference between these services and DTOs is that the domain primitives have been replaced with their wrapped ordinary primitives.
Additional context
No response
Hilla generator does not distinguish input and output types. So we need to provide support for both at the same time.
Let's take @JsonValue
into account when emitting TypeScript type. The @JsonCreator
paired with @JsonValue
would be supported automatically by Jackson runtime.
Hilla generator does not distinguish input and output types. So we need to provide support for both at the same time.
Let's take @JsonValue
into account when emitting TypeScript type. The @JsonCreator
paired with @JsonValue
would be supported automatically by Jackson runtime.
I don't know how feasible it is at code level, but would it be reasonable to automatically unpack all single-property objects when dealing with TS? That would mean that record Email(string value)
would be translated to a string
in TS, without any additional annotation required.
I think that it would be a nice way to simplify developers' life with those types.
The main drawback is that, if the object becomes record Email(String value, boolean verified)
, a new Email
type is introduced in TS and client code must be modified. But I'm not sure that this kind of change would happen frequently except in early development: single-property objects are likely domain primitives.
Automatic handling of single-property objects might make sense but I suspect we would still also need to support @JsonCreator
and @JsonValue
to allow customization.
In both cases, there are some further aspects that must be taken into account. One is different nullability between types.
For example, if a Person
has a nullable email
property of type Email
, and Email
has a non-nullable property of type String
, it's easy to guess that the email
must stay nullable. The opposite would be problematic, as it would allow to assign a null
value to a property which is not nullable, so domain primitives should host a non-nullable field.
Generics must be taken into account too: suppose we have a Id<T>
class and a Person
class that has and id
field of type Id<Long>
. We must be able to capture the Long
type.