Define how to handle `null` type
jonaslagoni opened this issue · comments
We need to figure out how we want to handle the null
type overall.
In JSON, null
is a different concept than "not present" and the types we generate need to reflect that. In most languages, null
or nil
is synonymous with "not present". In those languages I would expect code gen to use a custom type that represents the JSON null
value.
So, for null
I am not quite sure what is best. If we look at the behavior JSON schema has on the JSON data.
JSON Schema:
{ "properties": { "test": { "type": "null" } } }
validates correctly against
{ "test": null }
and
{ }
In a sense, removing the property completely makes sense to some extend here, as there are no values you want to access is there?
However, with require, removing the property is not possible and it needs to be present:
{ "required": ["test"], "properties": { "test": { "type": "null" } } }
validates correctly against
{ "test": null }
but not
{ }
In a sense, we have the same scenario anyway, where you don't really have an incentive to access such as property in any use-case is there (besides when the class is serialized the property needs to be there)?
In TS we can do the following:
class testType {
test: null
}
And for Java:
class testType {
final Object test = null;
}
We could also let custom serializable functionality handle it, and not generate the property at all:
class testType {
serialize(){
return '{test: null}'
}
}
I do however find that a bit weird 🤔 What are your thoughts?
You have to remember that JSON Schema describes JSON data and in JSON, null
is a value. null
is also a type, that contains one value: null
. It's just like boolean
which is a type that contains two values: true
and false
. This concept is not compatible with Java's null
. In Java, null
is not a type. Any type can be null
because null
means "there isn't anything here". It's equivalent to not defining a property in the instance.
So, in your example, the "test" property definitely needs to be generated because null
doesn't mean "there isn't anything here", it means there's a thing here called null
. So, in Java I would expect the following.
"test" is null and not required
class TestType {
JsonNull test = JsonNull.getInstance();
}
"test" is null and required
class TestType {
@NotNull
JsonNull test = JsonNull.getInstance();
}
I'm assuming JsonNull
is defined by the implementation to be a singleton class. Since there's no equivalent of JSON's null
in Java, we have to create something to represent that concept. TypeScript, on the other hand does have the same concept of null
as JSON because it's runtime is JavaScript. So, we don't need to create something to represent it.
"test" is null and not required
type TestType = {
test?: null;
}
"test" is null and required
type TestType = {
test: null;
}
Alright, that makes sense 👍 Thanks for clarifying 🙂
I realize this has been closed for a while, but I thought this was relevant.
null
is also important in how many APIs handle 'PUT' and even PATCH
requests. For these APIs, { "test": null }
means "clear the test
property, whereas { }
means do nothing.
In some API frameworks (like what's offered out of the box by .Net), this is difficult to discern, though, because they treat null
and "absent" as the same when deserializing JSON into models.